You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
asyncio.get_event_loop raises error instead of spawning new loop when no loop is running. #702
As you can see in the snippet above when run on un-patched asyncio it's returning a new loop. But uvloop raises error because of the method override which was not there in previous version inheriting the original new loop spawning function.
Got this issue with aiohttp.GunicornUVLoopWebWorker after updating uvloop to 0.22.1.
Note that uvloop==0.21.0 does work properly, and uvloop==0.22.1 does not.
For now added the following to my requirements.txt: uvloop!=0.22.1 — I hope the issue will be fixed in the next version.
Reacted by Adam Golinski, amon-shi and Alex Berber
Same issue here. It looks like 0.22.x's EventLoopPolicy overrides its base class asyncio.events.BaseDefaultEventLoopPolicy's get_event_loop function, and removes the creating new loop behavior.
Same here; uvicorn couldn't start. The thing took a while to figure out because it started to happen without code/image changes:
Traceback (most recent call last):
File "/usr/local/bin/uvicorn", line 7, in <module>
sys.exit(main())
^^^^^^
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 362, in main
run(**kwargs)
File "/usr/local/lib/python3.11/site-packages/uvicorn/main.py", line 386, in run
server.run()
File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 48, in run
loop = asyncio.get_event_loop()
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/uvloop/__init__.py", line 206, in get_event_loop
raise RuntimeError(
RuntimeError: There is no current event loop in thread 'MainThread'.
Reacted by Nándor Mátravölgyi, rivamarco, 4ndy, Anton Shurashov and Alex Berber
2025-10-29 13:49:42,186 [mlserver.parallel] INFO - New worker with PID 89 on default inference pool is now ready.
Process Worker-20:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
self.run()
File "/usr/local/lib/python3.11/site-packages/mlserver/parallel/worker.py", line 70, in run
self._ignore_signals()
File "/usr/local/lib/python3.11/site-packages/mlserver/parallel/worker.py", line 81, in _ignore_signals
loop = asyncio.get_event_loop()
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/uvloop/__init__.py", line 206, in get_event_loop
raise RuntimeError(
RuntimeError: There is no current event loop in thread 'MainThread'.
Process Worker-19:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
self.run()
File "/usr/local/lib/python3.11/site-packages/mlserver/parallel/worker.py", line 70, in run
self._ignore_signals()
File "/usr/local/lib/python3.11/site-packages/mlserver/parallel/worker.py", line 81, in _ignore_signals
loop = asyncio.get_event_loop()
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/uvloop/__init__.py", line 206, in get_event_loop
raise RuntimeError(
RuntimeError: There is no current event loop in thread 'MainThread'.
Process Worker-16:
This diff is fixing for me (copy from BaseDefaultEventLoopPolicy):
--- a/uvloop/__init__.py (index)+++ b/uvloop/__init__.py (working tree)@@ -193,6 +193,7 @@ def __getattr__(name: str) -> _typing.Any:
class _Local(threading.local):
_loop: _typing.Optional[_AbstractEventLoop] = None
+ _set_called: bool = False
def __init__(self) -> None:
self._local = self._Local()
@@ -202,6 +203,28 @@ def __getattr__(name: str) -> _typing.Any:
Returns an instance of EventLoop or raises an exception.
"""
+ if (self._local._loop is None and+ not self._local._set_called and+ threading.current_thread() is threading.main_thread()):+ stacklevel = 2+ try:+ f = _sys._getframe(1)+ except AttributeError:+ pass+ else:+ # Move up the call stack so that the warning is attached+ # to the line outside asyncio itself.+ while f:+ module = f.f_globals.get('__name__')+ if not (module == 'asyncio' or module.startswith('asyncio.')):+ break+ f = f.f_back+ stacklevel += 1+ import warnings+ warnings.warn('There is no current event loop',+ DeprecationWarning, stacklevel=stacklevel)+ self.set_event_loop(self.new_event_loop())+
if self._local._loop is None:
raise RuntimeError(
'There is no current event loop in thread %r.'
@@ -214,6 +237,7 @@ def __getattr__(name: str) -> _typing.Any:
self, loop: _typing.Optional[_AbstractEventLoop]
) -> None:
"""Set the event loop."""
+ self._local._set_called = True
if loop is not None and not isinstance(loop, _AbstractEventLoop):
raise TypeError(
f"loop must be an instance of AbstractEventLoop or None, "
So I ran into this and got curious why it's happening because it seems like a deliberate change. The change in behaviour has a logical reason. In py3.14 the default behaviour changed to raising a runtime error if there is no current loop. See https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.get_event_loop
Even in python 3.8 and up it already resulted in deprecation warnings to rely on this behaviour. So a proper fix for this would mean applying a version guard to emit a deprecation warning for older python. This would look something like:
importwarningsfromsysimportversion_info
...
defget_event_loop(self) ->_AbstractEventLoop:
"""Get the event loop for the current context. Returns an instance of EventLoop or raises an exception. """ifself._local._loopisNone:
ifversion_info[1] <14:
//makeneweventloop, probablythewaycpythondoesitas @shadchinsuggestedabove..
else:
raiseRuntimeError(
'There is no current event loop in thread %r.'%threading.current_thread().name
)
returnself._local._loop
That is assuming you want a version diff like this in your code. But otherwise it might be best to bump up the uvloop python version requirements.
Activity
MarSoft commentedon Oct 18, 2025
Got this issue with
aiohttp.GunicornUVLoopWebWorkerafter updatinguvloopto0.22.1.Note that
uvloop==0.21.0does work properly, anduvloop==0.22.1does not.For now added the following to my
requirements.txt:uvloop!=0.22.1— I hope the issue will be fixed in the next version.fantix commentedon Oct 18, 2025
Roger; I'm looking into this
andylin-hao commentedon Oct 20, 2025
Same issue here. It looks like 0.22.x's
EventLoopPolicyoverrides its base classasyncio.events.BaseDefaultEventLoopPolicy'sget_event_loopfunction, and removes the creating new loop behavior.Require uvloop version not equal to 0.22.0 and 0.22.1
danielbasso commentedon Oct 20, 2025
Same here; uvicorn couldn't start. The thing took a while to figure out because it started to happen without code/image changes:
DiegoD94 commentedon Oct 28, 2025
Same here, multiple project, including sglang and verl is impacted
alex-darrow commentedon Oct 29, 2025
Same here.
mlserver[mlflow]==1.7.0failed to startshadchin commentedon Jan 7, 2026
This diff is fixing for me (copy from BaseDefaultEventLoopPolicy):
Create loop in `get_event_loop` if needed
Pin uvloop<0.22 and add sanity test for it
Pin uvloop<0.22 and add sanity test for it
Pin uvloop<0.22 and add sanity test for it
Create missing loop in get_event_loop in main thread
Create missing loop in get_event_loop in main thread
Create missing loop in get_event_loop in main thread
Pin uvloop<0.22 and add sanity test for it
Pin uvloop<0.22 and add sanity test for it
Joris-DataExpert commentedon Jul 7, 2026
So I ran into this and got curious why it's happening because it seems like a deliberate change. The change in behaviour has a logical reason. In py3.14 the default behaviour changed to raising a runtime error if there is no current loop. See https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.get_event_loop
Even in python 3.8 and up it already resulted in deprecation warnings to rely on this behaviour. So a proper fix for this would mean applying a version guard to emit a deprecation warning for older python. This would look something like:
That is assuming you want a version diff like this in your code. But otherwise it might be best to bump up the uvloop python version requirements.