How to Fix 'async event loop error when scaling' in CrewAI (Python)
When CrewAI starts throwing an async event loop error when scaling, you’re usually hitting a Python async/runtime mismatch, not a CrewAI “scaling” bug. It shows up when you run agents/tasks inside an already-running event loop, or when you mix sync and async calls in the wrong place.
In practice, this happens most often in Jupyter, FastAPI, Streamlit, Celery workers, or any app that already owns the event loop. The symptom is usually some variation of RuntimeError: This event loop is already running or RuntimeError: asyncio.run() cannot be called from a running event loop.
The Most Common Cause
The #1 cause is calling asyncio.run() or blocking on async CrewAI code from inside an environment that already has an active loop.
CrewAI itself can be used in sync or async flows depending on how you wire it. The mistake is wrapping async execution the wrong way when your app framework is already managing concurrency.
Broken pattern vs fixed pattern
| Broken | Fixed |
|---|---|
Calls asyncio.run() inside a running loop | Uses await inside async context |
| Blocks on async code from sync code | Keeps the whole chain async |
| Common in notebooks / FastAPI endpoints | Works cleanly with CrewAI async tasks |
# BROKEN
import asyncio
from crewai import Agent, Task, Crew
agent = Agent(
role="Researcher",
goal="Find relevant policy details",
backstory="Insurance analyst"
)
task = Task(
description="Summarize claims policy changes",
expected_output="A short summary",
agent=agent
)
crew = Crew(agents=[agent], tasks=[task])
# This explodes if you're already inside an event loop
result = asyncio.run(crew.kickoff())
print(result)
# FIXED
from crewai import Agent, Task, Crew
agent = Agent(
role="Researcher",
goal="Find relevant policy details",
backstory="Insurance analyst"
)
task = Task(
description="Summarize claims policy changes",
expected_output="A short summary",
agent=agent
)
crew = Crew(agents=[agent], tasks=[task])
# Use this in a synchronous script only
result = crew.kickoff()
print(result)
If you are inside an async app, keep it async end-to-end:
# FIXED FOR ASYNC APPS
from crewai import Agent, Task, Crew
async def run_crew():
agent = Agent(
role="Researcher",
goal="Find relevant policy details",
backstory="Insurance analyst"
)
task = Task(
description="Summarize claims policy changes",
expected_output="A short summary",
agent=agent
)
crew = Crew(agents=[agent], tasks=[task])
result = await crew.kickoff_async()
return result
Other Possible Causes
1) Running CrewAI inside Jupyter or IPython with nested loops
Jupyter already runs an event loop. If you call asyncio.run() there, you’ll get the classic runtime error.
# BROKEN in notebooks
import asyncio
result = asyncio.run(crew.kickoff())
# FIXED in notebooks
result = await crew.kickoff_async()
2) Mixing sync and async tools inside one agent flow
If one tool is async and another is sync-blocking, the scheduler can behave badly under load.
# BROKEN: blocking I/O inside async flow
def fetch_claims():
import requests
return requests.get("https://api.example.com/claims").json()
# FIXED: use async client in async tool
import httpx
async def fetch_claims():
async with httpx.AsyncClient() as client:
r = await client.get("https://api.example.com/claims")
return r.json()
3) Spawning threads/processes around the crew execution
CrewAI plus multiprocessing can trigger event-loop conflicts if each worker tries to manage its own loop.
# BROKEN pattern
from multiprocessing import Pool
def worker(_):
return crew.kickoff()
with Pool(4) as p:
print(p.map(worker, range(4)))
Use one process per isolated runtime, or move orchestration outside the worker boundary.
4) Version mismatch between Python, CrewAI, and dependencies
Older versions of crewai, openai, pydantic, or Python itself can create weird runtime behavior that looks like an event-loop issue.
Check this first:
pip show crewai openai pydantic python-dotenv
python --version
If you’re on Python 3.12 with older dependency pins, upgrade intentionally and test again.
How to Debug It
- •
Read the exact traceback
- •If you see
RuntimeError: asyncio.run() cannot be called from a running event loop, you have a nested-loop problem. - •If you see
RuntimeError: This event loop is already running, your framework is already managing async execution.
- •If you see
- •
Check where
kickoff()is called- •In a plain script,
crew.kickoff()is fine. - •In FastAPI, Streamlit, Jupyter, or any
async def, useawait crew.kickoff_async()instead.
- •In a plain script,
- •
Search for hidden blocking calls
- •Look for
requests,time.sleep(), database clients without async support, or long CPU work inside tools. - •Replace them with async equivalents where possible.
- •Look for
- •
Temporarily reduce the system to one agent and one task
- •Remove retries, parallel tasks, and extra tools.
- •If the error disappears, the issue is orchestration complexity rather than CrewAI core execution.
Prevention
- •Keep your execution model consistent:
- •sync script →
crew.kickoff() - •async app →
await crew.kickoff_async()
- •sync script →
- •Avoid calling
asyncio.run()inside frameworks that already run an event loop. - •Use async-native libraries for HTTP and database access inside tools.
- •Pin tested versions of Python and CrewAI in production builds.
- •Add a small integration test that runs one agent/task in the same runtime as production.
If you want the shortest fix: stop wrapping CrewAI in asyncio.run() unless you are in a plain Python script. In most “scaling” cases, that one line is the problem.
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