crewAIInc / crewAIInc/crewAI

BaseTool.run / StructuredTool raise 'asyncio.run() cannot be called from a running event loop' when a tool returns a coroutine

Open
#6,978 1 comment 0 reactions 1 assignee View on GitHub

@Vidit-Ostwal is already working on this.

Since Aug 26, 2026.

Dominant language
Python
Stars
58.8k
Forks
8.5k
Avg merge
1d 15h
Merged PRs (30d)
109

Description

Description

Executing a tool whose _run (or wrapped func) returns a coroutine raises RuntimeError: asyncio.run() cannot be called from a running event loop whenever the call happens inside an already-running event loop — e.g. a FastAPI request handler, a Jupyter cell, or any async def. Synchronous scripts are unaffected, which is why this slips through basic testing but breaks every async-server deployment.

Location
  • lib/crewai/src/crewai/tools/base_tool.py:342BaseTool.run does result = asyncio.run(result)
  • lib/crewai/src/crewai/tools/base_tool.py:553Tool.run (the @tool decorator class), same pattern
  • lib/crewai/src/crewai/tools/structured_tool.py:441 and :446CrewStructuredTool.invoke, same pattern
result = self._run(*args, **kwargs)
if asyncio.iscoroutine(result):
    result = asyncio.run(result)   # <-- raises under a running loop
In-repo precedent (this is a known pattern here)

The codebase already solves exactly this elsewhere and the tool paths simply don't use it:

  • lib/crewai/src/crewai/tasks/llm_guardrail.py:24_run_coroutine_sync: try: asyncio.get_running_loop() and, if a loop is running, run the coroutine in a ThreadPoolExecutor(max_workers=1) via pool.submit(ctx.run, asyncio.run, coro).result(), else asyncio.run(coro).
  • Same guard in tools/mcp_native_tool.py:86, a2a/utils/agent_card.py, a2a/utils/delegation.py, mcp/tool_resolver.py, project/wrappers.py, project/annotations.py.
Reproduction
import asyncio
from crewai.tools import tool

@tool("echo")
async def echo(value: str) -> str:
    """Echo the value."""
    await asyncio.sleep(0.01)
    return f"echo: {value}"

async def handler():          # simulates a FastAPI route / Jupyter cell
    return echo.run(value="hi")

asyncio.run(handler())
# RuntimeError: asyncio.run() cannot be called from a running event loop

The same failure occurs with a BaseTool subclass whose _run returns a coroutine and with CrewStructuredTool.from_function(func=<async fn>).invoke(...).

Expected

run() / invoke() return the coroutine's result regardless of whether an event loop is already running, consistent with llm_guardrail._run_coroutine_sync.

Environment

crewai main (v1.15.15 snapshot), Python 3.13.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.