python runtime_error ai_generated true

RuntimeError: Event loop is closed

ID: python/event-loop-closed

Also available as: JSON · Markdown · 中文
80%Fix Rate
88%Confidence
0Evidence
2024-03-12First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
3.8 active — — —
3.9 active — — —
3.10 active — — —
3.11 active — — —
3.12 active — — —

Root Cause

An async operation was attempted after the event loop had already been closed, typically when reusing a loop object across multiple asyncio.run() calls or after calling loop.close() manually.

generic

中文

在事件循环已关闭后仍尝试执行异步操作,通常是因为在多次调用 asyncio.run() 时复用了同一个 loop 对象,或手动调用了 loop.close()。

Workarounds

  1. 95% success
    Use asyncio.run(main()) as the single entry point and never call loop.close() manually. asyncio.run creates and closes the loop for you.
    
    async def main():
        ...
    
    if __name__ == '__main__':
        asyncio.run(main())
  2. 85% success
    If you must reuse a loop (e.g. in tests), use asyncio.new_event_loop() per test and call loop.close() only in teardown:
    
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        loop.run_until_complete(coro())
    finally:
        loop.close()
  3. 90% success
    For aiohttp/aiofiles contexts, ensure the ClientSession is created and closed inside the same asyncio.run scope:
    
    async def main():
        async with aiohttp.ClientSession() as s:
            await s.get(url)
    asyncio.run(main())

Dead Ends

Common approaches that don't work:

  1. 65% fail

    Creates a new loop but the pending coroutine/task still references the old closed loop's internals, causing the same error deeper in the stack.

  2. 80% fail

    Swallows the error but the awaited work never completes, leading to silent data loss downstream.

  3. 90% fail

    Raises the same RuntimeError immediately because the loop state is terminal.