-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
Closed
Closed
Copy link
Labels
3.14bugs and security fixesbugs and security fixes3.15new features, bugs and security fixesnew features, bugs and security fixestopic-asynciotype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
The following code works fine on Python 3.13, but fails on Python 3.14 with a RuntimeError
related to asyncio tasks.
Minimal reproducible example
import asyncio
import inspect
from functools import wraps
from typing import Any, Awaitable, Callable, Union
import pytest
from multiprocess import Pipe, Process
from multiprocess.connection import Connection
import multiprocess as mp
mp.set_start_method(method="fork", force=True) # "spawn" works fine
class SubprocessError:
def __init__(self, ex: Exception) -> None:
self.exception = ex
def in_subprocess[T](func: Callable[..., Union[T, Awaitable[T]]]) -> Callable[..., Awaitable[T]]:
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> T:
return await calculate_in_subprocess(func, *args, **kwargs)
return wrapper
async def calculate_in_subprocess[T](func: Callable[..., Union[T, Awaitable[T]]], *args: Any, **kwargs: Any) -> T:
rx, tx = Pipe(duplex=False) # receiver & transmitter ; Pipe is one-way only
process = Process(target=_inner, args=(tx, func, *args), kwargs=kwargs)
process.start()
event = asyncio.Event()
loop = asyncio.get_event_loop()
loop.add_reader(fd=rx.fileno(), callback=event.set)
if not rx.poll(): # do not use process.is_alive() as condition here
await event.wait()
loop.remove_reader(fd=rx.fileno())
event.clear()
result = rx.recv()
process.join() # this blocks synchronously! make sure that process is terminated before you call join()
rx.close()
tx.close()
if isinstance(result, SubprocessError):
raise result.exception
return result
def _inner[T](tx: Connection, fun: Callable[..., Union[T, Awaitable[T]]], *a, **kw_args) -> None:
event_loop = None
if inspect.iscoroutinefunction(fun):
event_loop = asyncio.new_event_loop()
asyncio.set_event_loop(event_loop)
try:
if event_loop is not None:
res = event_loop.run_until_complete(fun(*a, **kw_args))
else:
res = fun(*a, **kw_args)
except Exception as ex:
tx.send(SubprocessError(ex=ex))
else:
tx.send(res)
@pytest.mark.asyncio
async def test_in_subprocess_simple_async():
@in_subprocess
async def f() -> int:
return 42
assert await f() == 42
Error message with Python 3.14
-------------------------------- live log call ---------------------------------
ERROR asyncio:base_events.py:1875 Exception in callback <_asyncio.TaskStepMethWrapper object at 0x7e71ba729ff0>()
handle: <Handle <_asyncio.TaskStepMethWrapper object at 0x7e71ba729ff0>()>
Traceback (most recent call last):
File "/usr/lib/python3.14/asyncio/events.py", line 94, in _run
self._context.run(self._callback, *self._args)
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: Cannot enter into task <Task pending name='Task-2' coro=<test_in_subprocess_simple_async.<locals>.f() running at foo.py:73> cb=[_run_until_complete_cb() at /usr/lib/python3.14/asyncio/base_events.py:181]> while another task <Task pending name='Task-1' coro=<test_in_subprocess_simple_async() running at foo.py:77> cb=[_run_until_complete_cb() at /usr/lib/python3.14/asyncio/base_events.py:181]> is being executed.
Environment
Installed packages (note: multiprocess
must be installed from GitHub):
certifi==2025.10.5
charset-normalizer==3.4.3
dill==0.4.0
docker==7.1.0
idna==3.10
iniconfig==2.1.0
multiprocess @ git+https://github.com/uqfoundation/multiprocess.git@02ea4bd36cac5013d70847815c92e1a736ef4a05
packaging==25.0
pluggy==1.6.0
Pygments==2.19.2
pytest==8.4.2
pytest-asyncio==1.2.0
pytest_docker_tools==3.1.9
requests==2.32.5
urllib3==2.5.0
And before you say, that the error is in the third-party lib multiprocess
and I should use multiprocessing
instead of multiprocess
: The bug even occurs with multiprocessing
(just replace the lib in the code example above). In Python 3.13 it will fail with a PicklingError
(which is expected for this example) but in Python 3.14 the RuntimeError: Cannot enter into task
will be thrown (see above). So this issue must be in Python 3.14.
CPython versions tested on:
3.14
Operating systems tested on:
Linux
Linked PRs
Metadata
Metadata
Assignees
Labels
3.14bugs and security fixesbugs and security fixes3.15new features, bugs and security fixesnew features, bugs and security fixestopic-asynciotype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Projects
Status
Done