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 crashes when tearing down the proactor event loop #83413
example.py: toy code demonstrating the difference.
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=Nonecreated_at=<Date2020-01-06.18:29:20.714>labels= ['3.10', '3.8', '3.9', 'type-crash', 'expert-asyncio']
title='asyncio crashes when tearing down the proactor event loop'updated_at=<Date2021-08-23.12:27:41.034>user='https://github.com/mikeshardmind'
When using asyncio.run for an asynchronous application utilizing ssl, on windows using the proactor event loop the application crashes when the loop is closed, completely skipping a finally block in the process.
This appears to be due to a __del__ method on transports used.
Manual handling of the event loop close while including a brief sleep appears to work as intended.
Both versions work fine with the selector event loop on linux.
This appears to be a somewhat known issue already, as it's been reported to aiohttp, however both the traceback, and the differing behavior seem to indicate this is an issue with the proactor event loop.
(On linux this still emits a resource warning without the sleep)
While I don't mind handling the loop cleanup, it seems like this case should also emit a resource warning rather than crashing.
If it's decided in which way this should be handled, I'm willing to contribute to or help test whatever direction the resolution for this should go.
Traceback included below, toy version of the problem attached as code.
Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x0000026463039820>
Traceback (most recent call last):
File "C:\Users\Michael\AppData\Local\Programs\Python\Python38\lib\asyncio\proactor_events.py", line 116, in __del__self.close()
File "C:\Users\Michael\AppData\Local\Programs\Python\Python38\lib\asyncio\proactor_events.py", line 108, in closeself._loop.call_soon(self._call_connection_lost, None)
File "C:\Users\Michael\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 715, in call_soonself._check_closed()
File "C:\Users\Michael\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 508, in _check_closed raiseRuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
I don't know if it would be feasible to add this to asyncio, but having a way to mark a resource as needing to be deterministically cleaned up at loop close could probably solve this as well as the underlying reasons why the transports are leaning on __del__ behavior which is an implementation detail (differing on, for example, pypy) and probably improve the overall usefulness of asyncio.run as well.
An addition like that probably requires more discussion than fixing this crash though.
mikeshardmind commented on Feb 18, 2020
mikeshardmindmannequin
MannequinAuthor
More actions
Linking out to a real-world example where this still manages to happen after running the event loop for an entire 2 seconds waiting for transports to close themselves after finishing everything else:
I looked into what would need to change to handle this in CPython, but am not confident in my ability to make such a PR after doing so, at least not without more discussion about it.
The best solution I considered involves making the only public way to make transports be tied to an event loop which hasn't been closed yet, and ensuring the event loop keeps a reference to each of these so that it can deterministically close them at loop finalization. Searching GitHub alone found that this would break way too many things.
If this can't be fully fixed, a solution which at least ensures this can't cause an uncatchable exception would be appreciated.
rmawatson commented on May 2, 2020
rmawatsonmannequin
Mannequin
More actions
This is also happening in other libraries besides aiohttp. Specifically xhttp on windows. There is an open issue at encode/httpx#914
Do we need to do anything more than suppress the error? If we're just failing to notify the event loop that we're closing because the loop is gone, does the notification even matter?
I can confirm the linked PR (gh-92842) fixes the issue as I originally described.
I still think that relying on __del__ here is not necessarily a good thing, but in the absence of expert opinion in the discussion at the time about addressing that, I didn't bother to look much further into it and just ensured all transports in my code were closed before leaving scope (side-stepping the issue in my own code, rather than fixing it as a whole.)
I'm running into a similar (but principly the same issue) when using asyncio.subprocess with pipes that are open when the script exits. If this belongs in a separate issue, let me know.
As a simple example using a IsolatedAsyncioTestCase and pytest
importasynciofromasyncio.subprocessimportcreate_subprocess_execfromunittestimportIsolatedAsyncioTestCaseimportsubprocessclassTest83413(IsolatedAsyncioTestCase):
asyncdefasyncSetUp(self) ->None:
self.p=awaitcreate_subprocess_exec('notepad', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# This will cause an error because we're not cleaning up the open pipesasyncdeftest_simple(self):
awaitasyncio.sleep(1)
assertTrueisFalse
Expected (my preferred) behavior is the simple warning that the process is being killed (the same as when no stdin/stdout/stderr arguments are provided):
Close running child process: kill <_WindowsSubprocessTransport closed pid=23660 running>
Reasonable (or more knowledgable) people could disagree on whether that's expected or not, but it would make reading my test outputs much easier :)
I cannot reproduce it on Windows 10. If you used non-Windows platform that we can be sure that this is caused not by proactor_events.py (covered by this issue) but by something else (so a new PR would be suitable).
Just for the record, here's my output for a clean build of 0771d71 (labeled as v3.11.0b5):
importasynciofrommcpimportClientSession, StdioServerParameters, stdio_clientasyncdefmain():
server_params=StdioServerParameters(
command="npx", args=["-y", "@playwright/mcp@latest"]
) # Or any other serverasyncwithstdio_client(server_params) as (read, write):
asyncwithClientSession(read, write) assession:
awaitsession.initialize()
print(awaitsession.list_tools())
awaitasyncio.sleep(2.0)
if__name__=="__main__":
asyncio.run(main())
Example traceback:
Exception ignored in: <function BaseSubprocessTransport.__del__ at 0x000001E2396C7CE0>
Traceback (most recent call last):
File "C:\Users\ashro\AppData\Roaming\uv\python\cpython-3.13.2-windows-x86_64-none\Lib\asyncio\base_subprocess.py", line 129, in __del__
_warn(f"unclosed transport {self!r}", ResourceWarning, source=self)
File "C:\Users\ashro\AppData\Roaming\uv\python\cpython-3.13.2-windows-x86_64-none\Lib\asyncio\base_subprocess.py", line 81, in __repr__
info.append(f'stdout={stdout.pipe}')
File "C:\Users\ashro\AppData\Roaming\uv\python\cpython-3.13.2-windows-x86_64-none\Lib\asyncio\proactor_events.py", line 80, in __repr__
info.append(f'fd={self._sock.fileno()}')
File "C:\Users\ashro\AppData\Roaming\uv\python\cpython-3.13.2-windows-x86_64-none\Lib\asyncio\windows_utils.py", line 102, in fileno
raise ValueError("I/O operation on closed pipe")
ValueError: I/O operation on closed pipe
Activity
mikeshardmind commentedon Jan 6, 2020
When using asyncio.run for an asynchronous application utilizing ssl, on windows using the proactor event loop the application crashes when the loop is closed, completely skipping a finally block in the process.
This appears to be due to a __del__ method on transports used.
Manual handling of the event loop close while including a brief sleep appears to work as intended.
Both versions work fine with the selector event loop on linux.
This appears to be a somewhat known issue already, as it's been reported to aiohttp, however both the traceback, and the differing behavior seem to indicate this is an issue with the proactor event loop.
(On linux this still emits a resource warning without the sleep)
While I don't mind handling the loop cleanup, it seems like this case should also emit a resource warning rather than crashing.
If it's decided in which way this should be handled, I'm willing to contribute to or help test whatever direction the resolution for this should go.
Traceback included below, toy version of the problem attached as code.
mikeshardmind commentedon Jan 7, 2020
I don't know if it would be feasible to add this to asyncio, but having a way to mark a resource as needing to be deterministically cleaned up at loop close could probably solve this as well as the underlying reasons why the transports are leaning on __del__ behavior which is an implementation detail (differing on, for example, pypy) and probably improve the overall usefulness of asyncio.run as well.
An addition like that probably requires more discussion than fixing this crash though.
mikeshardmind commentedon Feb 18, 2020
Linking out to a real-world example where this still manages to happen after running the event loop for an entire 2 seconds waiting for transports to close themselves after finishing everything else:
Cog-Creators/Red-DiscordBot#3560
As well as what we're currently looking at for a temporary solution for this at this point:
Cog-Creators/Red-DiscordBot#3566
I looked into what would need to change to handle this in CPython, but am not confident in my ability to make such a PR after doing so, at least not without more discussion about it.
The best solution I considered involves making the only public way to make transports be tied to an event loop which hasn't been closed yet, and ensuring the event loop keeps a reference to each of these so that it can deterministically close them at loop finalization. Searching GitHub alone found that this would break way too many things.
If this can't be fully fixed, a solution which at least ensures this can't cause an uncatchable exception would be appreciated.
rmawatson commentedon May 2, 2020
This is also happening in other libraries besides aiohttp. Specifically xhttp on windows. There is an open issue at encode/httpx#914
zooba commentedon Apr 28, 2021
I'm also seeing (and annoyed by) this.
Do we need to do anything more than suppress the error? If we're just failing to notify the event loop that we're closing because the loop is gone, does the notification even matter?
12 remaining items
mikeshardmind commentedon May 21, 2022
I can confirm the linked PR (gh-92842) fixes the issue as I originally described.
I still think that relying on
__del__here is not necessarily a good thing, but in the absence of expert opinion in the discussion at the time about addressing that, I didn't bother to look much further into it and just ensured all transports in my code were closed before leaving scope (side-stepping the issue in my own code, rather than fixing it as a whole.)arhadthedev commentedon Jun 30, 2022
This issue may be closed because the bug is fixed:
RuntimeError: Event loop is closedon script exit #92841spyoungtech commentedon Jul 29, 2022
I'm running into a similar (but principly the same issue) when using
asyncio.subprocesswith pipes that are open when the script exits. If this belongs in a separate issue, let me know.As a simple example using a
IsolatedAsyncioTestCaseandpytestBehaviors observed:
Exception in 3.11.0b5 running `pytest`
In 3.9.0 running `pytest`
Expected (my preferred) behavior is the simple warning that the process is being killed (the same as when no
stdin/stdout/stderrarguments are provided):Reasonable (or more knowledgable) people could disagree on whether that's expected or not, but it would make reading my test outputs much easier :)
arhadthedev commentedon Jul 30, 2022
Did you run the test on Linux or macOS?
I cannot reproduce it on Windows 10. If you used non-Windows platform that we can be sure that this is caused not by
proactor_events.py(covered by this issue) but by something else (so a new PR would be suitable).Just for the record, here's my output for a clean build of 0771d71 (labeled as
v3.11.0b5):fix: monkey-patch _ProactorBasePipeTransport to suppress warning
Remove workaround for asyncio.run
Remove workaround for asyncio.run
ashrobertsdragon commentedon Apr 7, 2025
This bug is still happening. People are getting it when using the MCP clients on Windows. [
Proactor Windows warning on cleanup when using stdio_client](url)
Example (from aforemention git repo:
Example traceback:
fix: prevent Windows CI hang by clearing httpx client before GC
fix: «тег не нужен» у единственного референса; обрыв соединения в жур…