How to Fix 'callback not firing when scaling' in CrewAI (TypeScript)
When callback not firing when scaling shows up in a CrewAI TypeScript app, it usually means your callback works in local runs but stops triggering once you add concurrency, multiple workers, or a scaled deployment. In practice, the issue is almost always about callback scope, process boundaries, or an event handler that never gets registered where the task actually runs.
The key thing to know: CrewAI callbacks are not magic global hooks. If your task execution moves to another worker, another container, or another runtime instance, the callback you attached in one place may never be visible in the place where the task is actually executed.
The Most Common Cause
The #1 cause is registering the callback on the wrong object or at the wrong lifecycle stage.
In CrewAI TypeScript, people often attach a callback to a local task instance and then scale execution through a queue, worker pool, or remote runner. The task completes, but the callback never fires because the worker executing Task.execute() never received that callback reference.
Broken vs fixed pattern
| Broken pattern | Fixed pattern |
|---|---|
| Callback attached only in the API process | Callback registered in the worker/runtime that executes the task |
| Task object serialized without callback | Callback passed as part of worker-side task construction |
| Assumes in-memory function survives scaling | Uses explicit event dispatch/logging across process boundaries |
// BROKEN: callback attached in one process,
// but execution happens elsewhere after scaling.
import { Agent, Task, Crew } from "@crewai/typescript";
const agent = new Agent({
name: "ClaimsAgent",
role: "claims analyst",
goal: "Review claim documents",
});
const onTaskComplete = (result: unknown) => {
console.log("Task completed:", result);
};
const task = new Task({
description: "Summarize claim file",
agent,
callback: onTaskComplete,
});
const crew = new Crew({
agents: [agent],
tasks: [task],
});
// Later this gets handed off to a worker / queue / remote executor
await crew.kickoff();
// FIXED: register the callback where the task is actually executed.
// If you're using workers, build the Task inside the worker process.
import { Agent, Task, Crew } from "@crewai/typescript";
function buildCrew() {
const agent = new Agent({
name: "ClaimsAgent",
role: "claims analyst",
goal: "Review claim documents",
});
const onTaskComplete = (result: unknown) => {
console.log("Task completed:", result);
// emit to queue / webhook / DB here
};
const task = new Task({
description: "Summarize claim file",
agent,
callback: onTaskComplete,
});
return new Crew({
agents: [agent],
tasks: [task],
});
}
await buildCrew().kickoff();
If you scale horizontally with Node cluster mode, Docker replicas, or serverless workers, treat callbacks as local runtime hooks only. For anything important, persist events explicitly.
Other Possible Causes
1. You’re passing an arrow function through serialization
Functions do not survive JSON serialization. If you enqueue a Task config and reconstruct it later with JSON.parse, your callback becomes undefined.
// BAD
const payload = JSON.stringify({
description: "Process document",
callback: () => console.log("done"),
});
// callback is gone after parse
Fix:
// GOOD
const payload = JSON.stringify({
description: "Process document",
callbackName: "onDocumentProcessed",
});
Then resolve it from a registry in the worker:
const callbacks = {
onDocumentProcessed: (result: unknown) => console.log(result),
};
2. Your task is failing before completion
If you see errors like:
- •
Error executing Task - •
UnhandledPromiseRejection - •
AgentExecutionError
the callback may never run because the task never reaches its success path.
try {
await crew.kickoff();
} catch (err) {
console.error("Crew failed before callback:", err);
}
Make sure you also handle failure callbacks if your version supports them.
3. The worker exits before async work finishes
A common bug is firing async work inside the callback and not awaiting it. Under load, Node can terminate or recycle the process before your side effect completes.
// BAD
callback: async (result) => {
saveToDb(result); // missing await
}
// GOOD
callback: async (result) => {
await saveToDb(result);
}
If you’re writing to Postgres, Redis, or S3 from inside callbacks, always await those calls.
4. Version mismatch between core and TypeScript wrapper
I’ve seen this when upgrading only part of the stack. One package expects callback, another expects a different hook signature or event name.
Check for mismatched versions:
{
"dependencies": {
"@crewai/typescript": "^0.4.0",
"@crewai/core": "^0.2.1"
}
}
If these are not meant to be paired together by your install docs, align them before debugging anything else.
How to Debug It
- •
Confirm whether execution is local or distributed
- •If it works locally but fails behind a queue or multiple pods, suspect process boundary loss.
- •Add logs at task creation and inside the worker that executes
kickoff().
- •
Log whether the callback exists at runtime
console.log("callback type:", typeof task.callback);If this prints
undefinedin your worker, you’ve found the problem. - •
Check for task failures before completion
- •Look for
AgentExecutionError, timeout errors, or rejected promises. - •A “missing callback” can just be a failed task path.
- •Look for
- •
Verify async side effects complete
- •Put logs before and after DB writes/webhooks inside the callback.
- •If “before” logs appear and “after” logs don’t, your issue is inside the callback body itself.
Prevention
- •Build callbacks inside the same runtime that executes CrewAI tasks.
- •Treat callbacks as local hooks; use queues/webhooks/DB events for cross-process reliability.
- •Add explicit logging around:
- •task creation
- •kickoff start/end
- •callback entry/exit
- •Pin compatible package versions and test after every upgrade of
@crewai/typescriptor related runtime packages.
If you want one rule to keep in mind: once you scale out of a single Node process, do not trust in-memory callbacks for critical workflow behavior. Use them for local orchestration only; use durable messaging for everything else.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit