# RuntimeError: Event loop is closed

- **ID:** `python/event-loop-closed`
- **Domain:** python
- **Category:** runtime_error
- **Verification:** ai_generated
- **Fix Rate:** 80%

## 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.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| 3.8 | active | — | — |
| 3.9 | active | — | — |
| 3.10 | active | — | — |
| 3.11 | active | — | — |
| 3.12 | active | — | — |

## 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

- **** — 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. (65% fail)
- **** — Swallows the error but the awaited work never completes, leading to silent data loss downstream. (80% fail)
- **** — Raises the same RuntimeError immediately because the loop state is terminal. (90% fail)
