How to Fix 'async event loop error during development' in CrewAI (Python)
What this error usually means
If you’re seeing async event loop error during development in CrewAI, you’re almost always dealing with an event loop conflict, not a CrewAI-specific bug. It usually shows up when you call async code from the wrong place, run notebooks or hot-reload servers, or mix asyncio.run() with an already running loop.
In practice, the stack trace often includes one of these:
- •
RuntimeError: asyncio.run() cannot be called from a running event loop - •
RuntimeError: This event loop is already running - •
RuntimeError: Task got Future attached to a different loop
The Most Common Cause
The #1 cause is wrapping CrewAI async execution inside asyncio.run() when you’re already inside an active loop.
This happens a lot in:
- •Jupyter notebooks
- •FastAPI endpoints
- •Streamlit apps
- •VS Code debug sessions with autoreload
Broken pattern vs fixed pattern
| Broken | Fixed |
|---|---|
Calls asyncio.run() from inside another async context | Uses await inside async functions |
| Creates tasks on one loop and runs them on another | Keeps execution on the same loop |
# broken.py
import asyncio
from crewai import Agent, Task, Crew, Process
agent = Agent(
role="Researcher",
goal="Research company data",
backstory="You are a careful analyst."
)
task = Task(
description="Summarize the latest quarterly filing.",
agent=agent
)
crew = Crew(
agents=[agent],
tasks=[task],
process=Process.sequential
)
async def handler():
# WRONG: if handler is already running in an event loop,
# this will raise:
# RuntimeError: asyncio.run() cannot be called from a running event loop
result = asyncio.run(crew.kickoff())
return result
# fixed.py
from crewai import Agent, Task, Crew, Process
agent = Agent(
role="Researcher",
goal="Research company data",
backstory="You are a careful analyst."
)
task = Task(
description="Summarize the latest quarterly filing.",
agent=agent
)
crew = Crew(
agents=[agent],
tasks=[task],
process=Process.sequential
)
async def handler():
# RIGHT: stay inside the current event loop
result = await crew.kickoff()
return result
If you’re in plain Python script code, use asyncio.run() only at the top level:
import asyncio
async def main():
result = await crew.kickoff()
print(result)
if __name__ == "__main__":
asyncio.run(main())
Other Possible Causes
1. Running CrewAI inside Jupyter without patching the loop
Jupyter already runs an event loop. If you call asyncio.run() there, it breaks immediately.
# broken in notebook cell
import asyncio
result = asyncio.run(crew.kickoff())
Fix it by awaiting directly:
# correct in notebook cell
result = await crew.kickoff()
If your notebook environment is older and doesn’t support top-level await, use nest_asyncio as a workaround:
import nest_asyncio
nest_asyncio.apply()
2. Mixing sync and async CrewAI APIs incorrectly
CrewAI has sync-style usage patterns and async usage patterns. If you call async methods from sync code without managing the loop correctly, you’ll hit runtime errors.
# broken
def run_crew():
return crew.kickoff_async() # returns coroutine, not result
output = run_crew()
Fix:
import asyncio
def run_crew():
return asyncio.run(crew.kickoff())
output = run_crew()
Or keep everything async:
async def run_crew():
return await crew.kickoff()
3. Creating objects on one thread/loop and executing on another
This shows up when background threads or reloaders are involved. You’ll often see:
- •
Task got Future attached to a different loop - •
attached to a different event loop
# broken pattern: create in one context, execute in another thread/loop
crew = Crew(agents=[agent], tasks=[task], process=Process.sequential)
If that object is later used inside another thread’s event loop, it can fail.
Fix by creating and running the crew in the same async context:
async def run():
agent = Agent(...)
task = Task(...)
crew = Crew(agents=[agent], tasks=[task], process=Process.sequential)
return await crew.kickoff()
4. Hot reload / dev server spawning duplicate loops
FastAPI with reload, Streamlit reruns, and some debugger setups can create multiple loops or restart state mid-flight.
uvicorn app:app --reload
If your startup code creates long-lived async resources at import time, move them into lifespan/startup hooks.
@app.on_event("startup")
async def startup():
app.state.crew = build_crew()
Avoid this:
# bad: module-level execution during import/reload
crew = build_crew()
result = asyncio.run(crew.kickoff())
How to Debug It
- •
Read the exact exception text
- •If you see
asyncio.run() cannot be called from a running event loop, you’re nesting loops. - •If you see
Future attached to a different loop, your objects are crossing contexts. - •If you see plain
This event loop is already running, you’re likely in Jupyter or an async server.
- •If you see
- •
Find where
asyncio.run()is called- •Search your codebase for
asyncio.run(. - •If it appears inside an endpoint, notebook cell, callback, or worker function that’s already async-aware, replace it with
await.
- •Search your codebase for
- •
Check whether your caller is already async
- •In FastAPI:
@app.get("/run") async def run(): return await crew.kickoff() - •In sync scripts:
if __name__ == "__main__": asyncio.run(main())
- •In FastAPI:
- •
Move object creation closer to execution
- •Build
Agent,Task, andCrewinside the same function that calls kickoff. - •This avoids cross-loop contamination during reloads or threaded execution.
- •Build
Prevention
- •Keep one rule:
awaitinside async functions,asyncio.run()only at the top level. - •Don’t create CrewAI runtime objects at import time if you’re using notebooks, reloaders, or web servers.
- •Add a small integration test that runs your CrewAI flow in the same environment as production entrypoints:
- •notebook cell if you develop there,
- •FastAPI endpoint if that’s your app,
- •CLI script if that’s how it ships.
If you want to stop chasing this class of bug entirely, standardize on one execution model per project: either fully synchronous entrypoints with one top-level asyncio.run(), or fully async request handlers with direct await.
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