python/cpython · error · RuntimeError

There is no current event loop in thread %r.

Error message

There is no current event loop in thread %r.

What it means

Raised by the slow path of asyncio.get_event_loop() when no event loop was ever set for the current thread and none is running. Since Python 3.10+, get_event_loop no longer auto-creates a loop in the main thread, so this RuntimeError is the standard failure for legacy sync-style calls.

Source

Thrown at Lib/asyncio/events.py:727

    """Set the running event loop.

    This is a low-level function intended to be used by event loops.
    This function is thread-specific.
    """
    # NOTE: this function is implemented in C (see _asynciomodule.c)
    _running_loop.loop_pid = (loop, os.getpid())


def _get_event_loop():
    """Return the event loop set for the current thread.

    Raise a RuntimeError if no event loop has been set for the current
    thread.  This is the slow path of get_event_loop(); the running loop
    is checked by the caller.
    """
    loop = _local._loop
    if loop is None:
        raise RuntimeError('There is no current event loop in thread %r.'
                            % threading.current_thread().name)
    return loop


def get_event_loop():
    """Return an asyncio event loop.

    When called from a coroutine or a callback (e.g. scheduled with call_soon
    or similar API), this function will always return the running event loop.

    If there is no running event loop set, the function will return
    the loop set by ``set_event_loop()``, or raise a RuntimeError if
    no loop has been set.
    """
    # NOTE: this function is implemented in C (see _asynciomodule.c)
    current_loop = _get_running_loop()
    if current_loop is not None:
        return current_loop

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Restructure around asyncio.run(main()) instead of get_event_loop()
  2. In a thread: loop = asyncio.new_event_loop(); asyncio.set_event_loop(loop)
  3. Pass the loop from the creating thread explicitly via run_coroutine_threadsafe(coro, loop)

Example fix

# before
loop = asyncio.get_event_loop()  # RuntimeError in thread

# after
def worker():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        return loop.run_until_complete(coro)
    finally:
        loop.close()
Defensive patterns

Strategy: validation

Validate before calling

import asyncio
try:
    loop = asyncio.get_event_loop()
    if loop.is_closed():
        loop = None
except RuntimeError:
    loop = None  # none set for this thread

Prevention

When it happens

Trigger: Calling asyncio.get_event_loop() in a worker threading.Thread, in a pytest fixture without asyncio mode, or from any sync context after set_event_loop(None)/loop.close() without setting a new one.

Common situations: Upgrading to Python 3.10/3.12 where implicit loop creation was removed; background threads doing get_event_loop().run_until_complete(); Jupyter users mixing asyncio APIs; tests that closed the loop in a prior test.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/c54a517846d64f80. Report an issue: GitHub.