Main Ecosystems
HomePython CorePandas ReferenceNumPy ScientificFastAPI & PydanticDjango Enterprise
More Ecosystems
Environment & SetupRequests & HTTPAsyncIO ConcurrencyObject-Oriented OOPPyTorch Deep LearningScikit-Learn MLFlask FrameworkWeb ScrapingDatabase & ORMDevOps & Docker

RuntimeError: This event loop is already running in asyncio

Verified FixPython 3.10+Python Native asyncioSilo: asyncio

Quick Fix / Solution Rapide

Use await main() directly inside existing async environments (like Jupyter or FastAPI) instead of calling asyncio.run().

Root Cause Analysis

This error occurs when Python tries to initialize and start a new event loop using asyncio.run(), but the current OS thread is already running an active event loop.

1. The Single Loop per Thread Model

Python's asyncio is designed around a single-threaded cooperative multitasking model where exactly one event loop runs per OS thread. When asyncio.run() is called, it creates a new event loop, sets it as the current loop, runs the passed coroutine to completion, and closes the loop. If an event loop is already executing tasks in the thread, starting a second loop is illegal and raises RuntimeError: This event loop is already running.

2. Interactive Environments and Async Frameworks

This error frequently occurs in interactive notebook environments like Jupyter, IPython, or Google Colab, where the notebook kernel itself already runs an asyncio event loop in the main thread. It also occurs in ASGI web servers (such as Uvicorn or Hypercorn) when synchronous route handlers inadvertently call asyncio.run().

3. Best Practices for Event Loop Management

In modern Python 3.10+, application code should define top-level async functions and rely on await rather than managing event loops manually. The standard design rule is to call asyncio.run() exactly once at the absolute entry point of a standalone CLI script.

4. Note de Reproductibilité

Cette erreur survient dans des environnements interactifs (Jupyter Notebook, IPython) ou des serveurs asynchrones déjà actifs. La reproduction exacte dépend de l'état d'exécution de la boucle d'événements globale du thread hôte.

Reproduction Code (MCVE)

Example: Bug Reproduction
import asyncio

async def task():
    return 42

async def main():
    # Calling asyncio.run() inside a running loop raises RuntimeError
    return asyncio.run(task())

asyncio.run(main())

Solution 1: Await Coroutines Directly Without asyncio.run()

When already inside an async coroutine or an active async context, simply await the target coroutine directly instead of trying to launch a new event loop.

Example: Recommended Solution
import asyncio

async def fetch_data():
    await asyncio.sleep(0.01)
    return {'status': 'ok', 'data': [1, 2, 3]}

async def main():
    # Directly await the coroutine on the active loop
    result = await fetch_data()
    print('Data fetched successfully:', result)

asyncio.run(main())

Solution 2: Inspect Running Loop State or Use create_task

In dual-mode libraries or notebook scripts, detect whether a loop is already running using asyncio.get_running_loop() to dispatch tasks via create_task.

Example: Alternative Solution
import asyncio

async def background_worker():
    return 'Task complete'

async def entry_point():
    try:
        loop = asyncio.get_running_loop()
        # When running inside a loop, schedule with create_task
        task = loop.create_task(background_worker())
        result = await task
        print('Scheduled via running loop:', result)
    except RuntimeError:
        # When no loop is running, run standalone
        result = asyncio.run(background_worker())
        print('Executed via standalone loop:', result)

asyncio.run(entry_point())

A common mistake is attempting to call async functions from synchronous helper functions using asyncio.run() deep inside the call stack. Contrast RuntimeError: This event loop is already running with RuntimeError: no running event loop, which occurs in Python 3.10+ when get_event_loop() is called with no active loop. Never share coroutine objects across multiple OS threads without using asyncio.run_coroutine_threadsafe(). In unit test suites, prefer pytest-asyncio fixtures over manual loop lifecycle management.