How to Fix 'callback not firing when scaling' in CrewAI (TypeScript)

By Cyprian AaronsUpdated 2026-04-21
callback-not-firing-when-scalingcrewaitypescript

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 patternFixed pattern
Callback attached only in the API processCallback registered in the worker/runtime that executes the task
Task object serialized without callbackCallback passed as part of worker-side task construction
Assumes in-memory function survives scalingUses 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

  1. 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().
  2. Log whether the callback exists at runtime

    console.log("callback type:", typeof task.callback);
    

    If this prints undefined in your worker, you’ve found the problem.

  3. Check for task failures before completion

    • Look for AgentExecutionError, timeout errors, or rejected promises.
    • A “missing callback” can just be a failed task path.
  4. 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/typescript or 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

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

Related Guides