High severity intermediate · Fix: 5-10 min

RuntimeError

asyncio.base_events.RuntimeError: Event loop is closed

What this error means
FastAPI async code raises RuntimeError because the asyncio event loop was closed prematurely or incorrectly managed.

Stack trace

traceback
Traceback (most recent call last):
  File "uvicorn/main.py", line 432, in run
    loop.run_until_complete(server.serve())
  File "/usr/lib/python3.9/asyncio/base_events.py", line 616, in run_until_complete
    self.run_forever()
  File "/usr/lib/python3.9/asyncio/base_events.py", line 574, in run_forever
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
QUICK FIX
Avoid calling asyncio.run() inside FastAPI async code and ensure background tasks finish before shutdown using lifespan events.

Why it happens

This error occurs when the asyncio event loop is closed but code attempts to run asynchronous tasks on it afterward. In FastAPI apps, this often happens if the event loop is closed prematurely by the server or if background tasks try to run after shutdown. Mismanagement of async lifecycle or improper shutdown sequences cause this.

Detection

Monitor logs for 'RuntimeError: Event loop is closed' during app shutdown or background task execution. Use try/except around async calls in shutdown events to catch this early.

Causes & fixes

1

Uvicorn or ASGI server closes the event loop before all async tasks complete

✓ Fix

Ensure all background tasks complete before shutdown by using lifespan events or proper shutdown hooks in FastAPI.

2

Calling asyncio.run() inside an already running event loop in FastAPI async context

✓ Fix

Avoid using asyncio.run() inside FastAPI async functions; instead, use await or create tasks with asyncio.create_task().

3

Improper use of event loop policy or manual loop closing in code

✓ Fix

Do not manually close the event loop; rely on the server's lifecycle management or use context managers properly.

Code: broken vs fixed

Broken - triggers the error
python
import asyncio
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    asyncio.run(asyncio.sleep(1))  # This line causes RuntimeError: event loop closed
    return {"message": "Hello World"}
Fixed - works correctly
python
import os
import asyncio
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    await asyncio.sleep(1)  # Fixed: use await instead of asyncio.run()
    return {"message": "Hello World"}

# Use environment variable for uvicorn command
if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)  # Proper server start
Replaced asyncio.run() with await to avoid creating a new event loop inside an existing one, preventing the 'event loop closed' RuntimeError.

Workaround

Wrap async calls in try/except RuntimeError and recreate the event loop if closed, but this is fragile and not recommended long-term.

Prevention

Use FastAPI lifespan events to manage startup and shutdown tasks cleanly, avoid manual event loop management, and never call asyncio.run() inside async FastAPI endpoints.

Python 3.9+ · fastapi >=0.60.0 · tested on 0.95.x
Verified 2026-04
Verify ↗

Community Notes

No notes yetBe the first to share a version-specific fix or tip.