python/cpython · error · TypeError

loop must be an instance of AbstractEventLoop or None, not '

Error message

loop must be an instance of AbstractEventLoop or None, not '{type(loop).__name__}'

What it means

asyncio.set_event_loop() validates its argument: it must be an AbstractEventLoop instance or None. Passing anything else (a factory, a coroutine, a mock, a loop policy) raises this TypeError immediately, guarding the thread-local loop slot from corrupt state.

Source

Thrown at Lib/asyncio/events.py:755

    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
    return _get_event_loop()


def set_event_loop(loop):
    """Set the event loop for the current thread to loop.

    If loop is None, the current event loop is unset.
    """
    if loop is not None and not isinstance(loop, AbstractEventLoop):
        raise TypeError(f"loop must be an instance of AbstractEventLoop or None, not '{type(loop).__name__}'")
    _local._loop = loop


def new_event_loop():
    """Create and return a new event loop object."""
    if sys.platform == 'win32':
        from .windows_events import EventLoop
    else:
        from .unix_events import EventLoop
    return EventLoop()


# Alias pure-Python implementations for testing purposes.
_py__get_running_loop = _get_running_loop
_py__set_running_loop = _set_running_loop
_py_get_running_loop = get_running_loop
_py_get_event_loop = get_event_loop

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Instantiate the loop: asyncio.set_event_loop(asyncio.new_event_loop())
  2. To clear the thread's loop, pass None explicitly
  3. In tests, use unittest.mock patches with spec, or pytest-asyncio fixtures instead of manual set_event_loop

Example fix

# before
asyncio.set_event_loop(asyncio.new_event_loop)  # passed the function

# after
asyncio.set_event_loop(asyncio.new_event_loop())  # passed an instance
Defensive patterns

Strategy: type-guard

Validate before calling

import asyncio
assert isinstance(loop, (asyncio.AbstractEventLoop, type(None)))

Type guard

def is_loop_or_none(obj) -> bool:
    return obj is None or isinstance(obj, asyncio.AbstractEventLoop)

Prevention

When it happens

Trigger: Calling set_event_loop(new_event_loop) with missing parentheses, passing the EventLoop class instead of an instance, passing a concurrent.futures executor, or a Mock object in tests without spec.

Common situations: Typos in test setup; copying example code that stored a loop factory; mocking asyncio and forgetting spec=asyncio.AbstractEventLoop; passing the result of uvloop.Loop (class) instead of uvloop.new_event_loop().

Related errors


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