How to Fix 'async event loop error' in CrewAI (TypeScript)

By Cyprian AaronsUpdated 2026-04-21
async-event-loop-errorcrewaitypescript

When you see async event loop error in CrewAI TypeScript, it usually means your code is trying to start or reuse an async runtime in a way the SDK does not expect. In practice, this shows up when you call crew.kickoff() from inside another async flow, mix sync and async APIs, or run CrewAI in an environment with conflicting event loop behavior.

The fix is usually not “add more await”. It’s about making sure CrewAI is called from the right entrypoint, with one clean async boundary, and no nested loop management.

The Most Common Cause

The #1 cause is wrapping CrewAI execution inside another async runner or calling the wrong method from the wrong context.

Typical symptoms include errors like:

  • Error: async event loop error
  • Error: Cannot run the event loop while another loop is running
  • Error: Event loop is already running
  • TypeError: crew.kickoffSync is not a function when using the wrong API shape

Broken vs fixed pattern

Broken patternFixed pattern
Calling sync-style execution from inside an async handlerUse one top-level async function main() and await crew.kickoff()
Mixing kickoffSync() and async tool callsKeep the whole flow async
Starting CrewAI inside a callback that already owns the loopMove orchestration to the top-level entrypoint
// BROKEN
import { Crew, Agent, Task } from "@crewai/typescript";

const agent = new Agent({
  name: "SupportAgent",
  role: "Customer support",
  goal: "Answer support questions",
});

const task = new Task({
  description: "Summarize the ticket",
  agent,
});

const crew = new Crew({
  agents: [agent],
  tasks: [task],
});

async function handleRequest() {
  // This often triggers loop/runtime conflicts in certain runtimes
  const result = crew.kickoffSync();
  console.log(result);
}

handleRequest();
// FIXED
import { Crew, Agent, Task } from "@crewai/typescript";

const agent = new Agent({
  name: "SupportAgent",
  role: "Customer support",
  goal: "Answer support questions",
});

const task = new Task({
  description: "Summarize the ticket",
  agent,
});

const crew = new Crew({
  agents: [agent],
  tasks: [task],
});

async function main() {
  const result = await crew.kickoff();
  console.log(result);
}

main().catch((err) => {
  console.error("CrewAI failed:", err);
  process.exitCode = 1;
});

If your code currently uses kickoffSync() anywhere in a Node service, remove it first. In TypeScript projects, especially those using tools like Next.js, NestJS, or serverless handlers, sync wrappers are where this problem starts.

Other Possible Causes

1. Running CrewAI inside an environment with its own event loop

This happens in REPLs, notebook-style environments, and some server frameworks.

// Example: calling kickoff inside a framework lifecycle hook
app.get("/run", async (_req, res) => {
  const result = await crew.kickoff();
  res.json({ result });
});

If the framework already manages concurrency in a special way, isolate CrewAI execution into a service layer and avoid nested runtime setup.

2. Double invocation of the same crew instance

Reusing one shared Crew object across concurrent requests can produce weird runtime behavior.

// BAD
const sharedCrew = new Crew({ agents: [agent], tasks: [task] });

await Promise.all([
  sharedCrew.kickoff(),
  sharedCrew.kickoff(),
]);

Use one instance per request or serialize execution:

// GOOD
async function runCrew() {
  const crew = new Crew({ agents: [agent], tasks: [task] });
  return await crew.kickoff();
}

3. Mismatched package versions

A version mismatch between @crewai/typescript, Node.js, and transitive dependencies can surface as event loop failures instead of clean type errors.

{
  "dependencies": {
    "@crewai/typescript": "^0.1.0"
  },
  "engines": {
    "node": "18.x"
  }
}

Check for incompatible combinations:

  • old SDK with newer Node runtime
  • multiple copies of the same dependency in lockfile
  • mixed ESM/CJS module settings

4. Top-level await used incorrectly in CommonJS

If your project is compiled to CommonJS but you write ESM-style top-level await patterns, runtime behavior gets messy fast.

// BAD in CommonJS output
const result = await crew.kickoff();
console.log(result);

Wrap it:

async function main() {
  const result = await crew.kickoff();
  console.log(result);
}

main();

How to Debug It

  1. Find the exact call site

    • Search for kickoff, kickoffSync, and any wrapper functions.
    • The bug is usually at the first place you cross into CrewAI execution.
  2. Check whether you are nesting async contexts

    • If you’re inside a route handler, queue worker, cron job, or framework hook, simplify it.
    • Temporarily move execution into a plain Node script:
      async function main() {
        await crew.kickoff();
      }
      main();
      
  3. Verify whether you’re reusing state

    • Don’t share one global Crew instance across concurrent jobs.
    • Instantiate per request if there’s any chance of parallel runs.
  4. Print runtime details

    • Log these before kickoff:
      console.log(process.version);
      console.log(process.env.NODE_ENV);
      console.log(typeof window === "undefined" ? "node" : "browser");
      
    • If this runs anywhere other than plain Node.js server-side code, suspect environment conflict first.

Prevention

  • Use one async entrypoint per job:
    • async function main() { await crew.kickoff(); }
  • Keep CrewAI isolated behind a service class:
    • don’t call it directly from UI components or nested callbacks
  • Pin versions and test upgrades together:
    • Node.js version, TypeScript target/module settings, and @crewai/typescript should move as a unit

If you want this to stay stable in production, treat CrewAI like any other job runner: one execution boundary, no shared mutable instance across concurrent requests, and no sync wrappers around async work.


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