Report #16106
[bug\_fix] Asyncio 'no current event loop' in threads or subprocesses
Use \`asyncio.run\(\)\` in the main thread, or in a new thread manually create a loop with \`asyncio.new\_event\_loop\(\)\` and set it with \`asyncio.set\_event\_loop\(loop\)\`. Do not use deprecated \`asyncio.get\_event\_loop\(\)\` in new threads.
Journey Context:
A developer writes a FastAPI endpoint that spawns a background thread using \`threading.Thread\` to run a CPU-intensive task. Inside the thread function, they need to call an async library function, so they use \`asyncio.get\_event\_loop\(\).run\_until\_complete\(coro\(\)\)\`. In local testing with \`uvicorn --reload\`, it works because the main thread has a loop. In production with Gunicorn using Uvicorn workers, the background thread crashes with \`RuntimeError: There is no current event loop in thread 'Thread-1'\`. The developer adds debugging \`print\(threading.current\_thread\(\)\)\` and realizes the worker runs the thread. They read the Python 3.10\+ docs and see \`get\_event\_loop\(\)\` no longer creates a new loop automatically in threads without one. The fix is to change the threaded function to create its own loop: \`loop = asyncio.new\_event\_loop\(\); asyncio.set\_event\_loop\(loop\); result = loop.run\_until\_complete\(coro\(\)\)\`. Alternatively, they refactor to use \`asyncio.run\_coroutine\_threadsafe\(\)\` to submit the coroutine to the main thread's existing loop if appropriate. The root cause is that \`asyncio\` event loops are thread-local; each thread must explicitly create and set its own loop if not using \`asyncio.run\(\)\`, which is only valid in the main thread and creates a new loop each time.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T01:50:28.245474+00:00— report_created — created