How to Fix 'async event loop error during development' in AutoGen (Python)
If you’re seeing RuntimeError: This event loop is already running or asyncio.run() cannot be called from a running event loop while developing with AutoGen in Python, you’re hitting a loop-management problem, not an AutoGen-specific bug. It usually shows up in notebooks, FastAPI apps, Streamlit, or any environment that already owns the asyncio loop.
The fix is usually simple: stop nesting event-loop entry points and make your AutoGen calls match the runtime you’re in.
The Most Common Cause
The #1 cause is calling asyncio.run() inside an environment that already has an active event loop.
This happens a lot when people copy a working script into Jupyter, VS Code notebooks, FastAPI handlers, or other async frameworks. AutoGen’s async APIs are fine; the problem is how they’re invoked.
Broken vs fixed pattern
| Broken pattern | Right pattern |
|---|---|
Calls asyncio.run() from inside an async context | Uses await inside async code |
| Tries to start a new loop when one already exists | Reuses the existing loop |
# ❌ Broken: nested event loop
import asyncio
from autogen_agentchat.agents import AssistantAgent
agent = AssistantAgent(
name="assistant",
model_client=model_client,
)
async def main():
result = await agent.run(task="Summarize this document")
print(result)
# This fails in notebooks / async apps:
asyncio.run(main())
# ✅ Fixed: use await inside an async context
from autogen_agentchat.agents import AssistantAgent
agent = AssistantAgent(
name="assistant",
model_client=model_client,
)
async def main():
result = await agent.run(task="Summarize this document")
print(result)
# In notebooks:
# await main()
# In plain Python scripts:
import asyncio
if __name__ == "__main__":
asyncio.run(main())
If you’re using older AutoGen APIs like AssistantAgent, UserProxyAgent, or GroupChatManager, the same rule applies. Don’t wrap async calls in another asyncio.run() if your app framework already started the loop.
Other Possible Causes
1) Mixing sync and async AutoGen APIs
A common mistake is calling async methods from sync code without understanding which side owns the loop.
# ❌ Broken
result = agent.run(task="Analyze this claim")
print(result)
# ✅ Fixed
async def main():
result = await agent.run(task="Analyze this claim")
print(result)
If the method returns a coroutine, it must be awaited. If you ignore that and try to treat it like a normal function, you’ll get confusing runtime behavior.
2) Running AutoGen inside Jupyter without top-level await
Jupyter already runs an event loop. That means asyncio.run() will fail immediately.
# ❌ Broken in notebook cells
import asyncio
asyncio.run(main())
# ✅ Fixed in notebook cells
await main()
If your notebook code needs helper functions, keep them async all the way down. Don’t “escape” back to sync just to call AutoGen.
3) Calling AutoGen from FastAPI/Starlette handlers incorrectly
FastAPI route handlers can be async. If you call asyncio.run() inside them, you’ll trigger the error.
# ❌ Broken
from fastapi import FastAPI
app = FastAPI()
@app.post("/summarize")
async def summarize():
return asyncio.run(agent.run(task="Summarize this policy"))
# ✅ Fixed
@app.post("/summarize")
async def summarize():
return await agent.run(task="Summarize this policy")
This is one of the most common production mistakes when developers move a notebook prototype into an API service.
4) Using legacy code that starts its own loop
Some older samples use patterns like loop = asyncio.get_event_loop() and then run_until_complete(). That can break depending on Python version and hosting environment.
# ❌ Fragile / often broken
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
# ✅ Safer for scripts
if __name__ == "__main__":
asyncio.run(main())
If you’re inside an existing framework-managed loop, don’t manage the loop yourself at all.
How to Debug It
- •
Check where the error happens
- •If it appears in Jupyter, Streamlit, FastAPI, or an IDE interactive console, assume there is already a running loop.
- •If it appears in a plain
.pyscript, look for nested calls toasyncio.run()orrun_until_complete().
- •
Find every event-loop entry point
- •Search for:
- •
asyncio.run( - •
loop.run_until_complete( - •
nest_asyncio
- •
- •You want exactly one top-level loop owner.
- •Search for:
- •
Verify whether the AutoGen method is async
- •If you see code like:
check the docs or type hints.result = agent.run(...) - •For modern AutoGen agent classes such as
AssistantAgent, most execution paths are async and needawait.
- •If you see code like:
- •
Print the actual exception
- •The two messages that matter are:
- •
RuntimeError: This event loop is already running - •
RuntimeError: asyncio.run() cannot be called from a running event loop
- •
- •If you see either one, stop looking at AutoGen internals and inspect your app boundary first.
- •The two messages that matter are:
Prevention
- •Keep your project consistently async once you adopt AutoGen’s async APIs.
- •Use this rule:
- •scripts: one top-level
asyncio.run(main()) - •notebooks/frameworks: top-level
await
- •scripts: one top-level
- •Avoid copying notebook code directly into FastAPI or background worker code without removing nested loop calls.
- •Add a small integration test that runs your agent entrypoint in the same environment you deploy to.
If you want a stable mental model: AutoGen doesn’t want “more asyncio.” It wants the right asyncio boundary. Once you stop starting loops inside loops, this error disappears fast.
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