How to Fix 'async event loop error when scaling' in CrewAI (Python)

By Cyprian AaronsUpdated 2026-04-21
async-event-loop-error-when-scalingcrewaipython

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

BrokenFixed
Calls asyncio.run() inside a running loopUses await inside async context
Blocks on async code from sync codeKeeps the whole chain async
Common in notebooks / FastAPI endpointsWorks 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

  1. 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.
  2. Check where kickoff() is called

    • In a plain script, crew.kickoff() is fine.
    • In FastAPI, Streamlit, Jupyter, or any async def, use await crew.kickoff_async() instead.
  3. 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.
  4. 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()
  • 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

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