Skip to content
Latchkey

pytest-asyncio "RuntimeError: Event loop is closed" in CI

Async code tried to schedule work on an event loop that pytest-asyncio had already closed. This happens when a fixture or resource outlives the loop it was created on, or when loop scope and fixture scope disagree.

What this error means

An async test or its teardown fails with "RuntimeError: Event loop is closed", sometimes only on teardown of a session/module-scoped async fixture.

pytest
RuntimeError: Event loop is closed
  ... during teardown of <async fixture 'client'>

Common causes

A resource outlives its event loop

An async client/connection created on a function-scoped loop is used or closed after that loop is gone.

Loop scope and fixture scope mismatch

A session-scoped async fixture with a function-scoped loop (or vice versa) ends up touching a closed loop.

How to fix it

Align async fixture and loop scope

Set a consistent loop scope so async fixtures and the loop share a lifetime.

pyproject.toml
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"

Create and close resources within the same loop

Construct async clients inside the test (or a same-scope fixture) so they live and die on one loop.

tests/conftest.py
@pytest_asyncio.fixture
async def client():
    async with httpx.AsyncClient() as c:
        yield c

How to prevent it

  • Keep async fixture scope and loop scope consistent.
  • Open and close async resources on the same loop.
  • Pin pytest-asyncio and set its loop-scope config explicitly.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →