Error database

RuntimeError: This event loop is already running / asyncio.run() cannot be called from a running event loop

Jupyter already runs an asyncio event loop, and asyncio.run() refuses to nest inside it. Await directly in the cell — or apply nest_asyncio for libraries that insist.

The message you saw
RuntimeError: This event loop is already running / asyncio.run() cannot be called from a running event loop

By Updated

The error

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

Older wording of the same collision:

Output
RuntimeError: This event loop is already running

What it means

asyncio runs asynchronous code on an event loop — a scheduler that one thread runs one of. asyncio.run() creates a fresh loop and blocks until done, and it refuses to start inside a thread whose loop is already running. Jupyter's kernel runs on exactly such a loop. So any asyncio.run(...) in a notebook cell — yours, or inside a library you called — collides with the loop that is already spinning.

This bites AI developers constantly: async LLM SDK methods, LangChain and LlamaIndex async APIs, web scrapers and Playwright all reach for the loop.

Why it happens

Code written for scripts uses the standard script idiom (asyncio.run(main())) and gets pasted into a notebook, where the idiom is wrong. Or a library method you called internally does asyncio.run / loop.run_until_complete — correct in scripts, broken under Jupyter — and the traceback points deep inside the library.

How to fix it

1. In a notebook, await directly. Jupyter supports top-level await in cells:

python
result = await client.messages.create(   # no asyncio.run wrapper
    model=MODEL, max_tokens=512,
    messages=[{"role": "user", "content": "hello"}],
)

Anywhere a script would write asyncio.run(coro()), a cell writes await coro(). This is the clean fix for your own code.

2. When a library calls asyncio.run internally, apply nest_asyncio.

bash
pip install nest_asyncio
python
import nest_asyncio
nest_asyncio.apply()

Run once near the top of the notebook. It patches the loop to tolerate nesting, unblocking libraries whose sync wrappers hide async plumbing — the LlamaIndex and scraping-tool cases. Keep it a notebook-only tool; production services deserve fix 3.

3. In scripts and services, structure async properly instead. One asyncio.run(main()) at the entry point, await everywhere inside, and no nested run calls. If sync code must call async code in a running-loop world (an async web framework, for example), that is a design decision — schedule it on the loop (asyncio.create_task, or run_coroutine_threadsafe from another thread) rather than fighting the nesting rule.

4. Use the sync client when you never wanted async. The LLM SDKs offer both: Anthropic()/OpenAI() are synchronous and involve no loop at all. Async earns its complexity for concurrent request fan-out; a sequential notebook rarely needs it.

How to prevent it

Learn the two idioms as a pair: scripts wrap once with asyncio.run; notebooks await at top level. When adopting an async library, check its notebook guidance — mature ones document the nest_asyncio requirement or provide notebook-safe entry points.