How to Fix 'async event loop error during development' in AutoGen (TypeScript)

By Cyprian AaronsUpdated 2026-04-21
async-event-loop-error-during-developmentautogentypescript

When you see async event loop error during development in AutoGen TypeScript, it usually means you’re trying to start or reuse an async workflow in a way the runtime can’t safely schedule. In practice, this shows up when you mix top-level execution, nested await calls, or event handlers that trigger AutoGen agents more than once.

The error is usually not in AutoGen itself. It’s almost always a lifecycle problem in your app code: how the agent is created, where the runner is started, and whether you’re accidentally re-entering the same async path.

The Most Common Cause

The #1 cause is starting AutoGen inside a callback or module scope that gets executed repeatedly, especially during development with hot reload, watchers, or request handlers.

A common failure pattern looks like this:

BrokenFixed
Starts agent work at import timeWraps execution in a single main()
Re-enters on every file reloadGuards startup and awaits once
Hard to control lifecycleClear entrypoint and shutdown
// ❌ Broken: runs as soon as the module is imported
import { AssistantAgent } from "@autogen/agent";
import { OpenAIChatCompletionClient } from "@autogen/openai";

const modelClient = new OpenAIChatCompletionClient({
  model: "gpt-4o-mini",
  apiKey: process.env.OPENAI_API_KEY!,
});

const agent = new AssistantAgent({
  name: "assistant",
  modelClient,
});

const result = await agent.run("Summarize this document");
console.log(result);
// ✅ Fixed: isolate startup in one async entrypoint
import { AssistantAgent } from "@autogen/agent";
import { OpenAIChatCompletionClient } from "@autogen/openai";

async function main() {
  const modelClient = new OpenAIChatCompletionClient({
    model: "gpt-4o-mini",
    apiKey: process.env.OPENAI_API_KEY!,
  });

  const agent = new AssistantAgent({
    name: "assistant",
    modelClient,
  });

  const result = await agent.run("Summarize this document");
  console.log(result);
}

main().catch((err) => {
  console.error("AutoGen run failed:", err);
  process.exit(1);
});

If you’re using tsx, nodemon, Next.js API routes, or a dev server with hot reload, import-time execution is a trap. You end up with overlapping async runs and errors like:

  • Error: Cannot start event loop while another run is active
  • Error: Event loop already running
  • UnhandledPromiseRejectionWarning
  • AutoGenRuntimeError: agent.run() called while previous invocation is still active

Other Possible Causes

1. Calling run() twice without waiting for the first call

This happens when two requests hit the same singleton agent.

// ❌ Broken
const agent = new AssistantAgent({ name: "assistant", modelClient });

app.post("/chat", async (req, res) => {
  const p1 = agent.run(req.body.message);
  const p2 = agent.run("follow-up"); // overlaps
  res.json({ first: await p1, second: await p2 });
});
// ✅ Fixed
app.post("/chat", async (req, res) => {
  const first = await agent.run(req.body.message);
  res.json({ first });
});

If you need concurrency, create isolated agent instances per request.

2. Reusing mutable shared state across requests

AutoGen agents often hold conversation state. Sharing one instance globally can break under parallel traffic.

// ❌ Broken
let sharedAgent = new AssistantAgent({ name: "assistant", modelClient });

export async function handleChat(message: string) {
  return sharedAgent.run(message);
}
// ✅ Fixed
export async function handleChat(message: string) {
  const agent = new AssistantAgent({ name: "assistant", modelClient });
  return agent.run(message);
}

If state must be shared, store it explicitly in your own persistence layer instead of relying on one live object.

3. Mixing top-level await with dev tooling that reloads modules

Some TypeScript dev setups execute modules multiple times during HMR or restart cycles.

// ❌ Broken
const result = await team.run("Plan a migration");
console.log(result);
// ✅ Fixed
async function bootstrap() {
  const result = await team.run("Plan a migration");
  console.log(result);
}

bootstrap();

This is especially common when using ESM plus watch mode. Keep all side effects behind a function boundary.

4. Using an unsupported runtime pattern in tests

Jest and Vitest can create confusing async behavior if tests share setup across files.

// ❌ Broken test setup
beforeAll(async () => {
  global.agentResult = await agent.run("test");
});
// ✅ Fixed test setup
test("agent responds", async () => {
  const result = await agent.run("test");
  expect(result).toBeDefined();
});

If your test framework runs files in parallel, avoid shared singleton agents unless they are read-only and explicitly safe.

How to Debug It

  1. Find where run() is called

    • Search for agent.run(, team.run(, or any AutoGen entrypoint.
    • Check whether it’s inside module scope, a request handler, or a callback that can fire multiple times.
  2. Log invocation count

    • Add a counter around the call site.
    • If you see two logs before the first call completes, you’ve found the overlap.
let calls = 0;

async function runOnce() {
  calls += 1;
  console.log("AutoGen run count:", calls);
  return agent.run("hello");
}
  1. Check your dev server behavior

    • If you use hot reload, verify whether the file is being executed more than once.
    • Temporarily disable HMR or watch mode and rerun.
  2. Isolate the agent

    • Move all AutoGen initialization into one plain script.
    • Run it with Node directly:
      node dist/main.js
      
    • If the error disappears, your framework lifecycle is the problem.

Prevention

  • Put all AutoGen startup logic behind a single main() or request-scoped function.
  • Avoid shared mutable agent instances unless you control concurrency explicitly.
  • In dev mode, assume your module may be loaded more than once and keep side effects out of top-level scope.
  • For web apps, treat each request as isolated unless you intentionally build session state around persistence.

If you want one rule to remember: don’t let AutoGen start itself on import. That pattern causes most async event loop errors in TypeScript development environments.


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