Title: Asyncio: fork() in coroutine causes bad file descriptor · Issue #130442 · python/cpython · GitHub
Open Graph Title: Asyncio: fork() in coroutine causes bad file descriptor · Issue #130442 · python/cpython
X Title: Asyncio: fork() in coroutine causes bad file descriptor · Issue #130442 · python/cpython
Description: Bug report Bug description: Here is a simple repro: import asyncio import os async def main(): pid = os.fork() if pid: os.waitpid(pid, 0) asyncio.run(main()) The traceback looks like: Traceback (most recent call last): File "/usr/local/C...
Open Graph Description: Bug report Bug description: Here is a simple repro: import asyncio import os async def main(): pid = os.fork() if pid: os.waitpid(pid, 0) asyncio.run(main()) The traceback looks like: Traceback (mo...
X Description: Bug report Bug description: Here is a simple repro: import asyncio import os async def main(): pid = os.fork() if pid: os.waitpid(pid, 0) asyncio.run(main()) The traceback looks like: Traceback (mo...
Opengraph URL: https://github.com/python/cpython/issues/130442
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Asyncio: fork() in coroutine causes bad file descriptor","articleBody":"# Bug report\n\n### Bug description:\n\nHere is a simple repro:\n```python\nimport asyncio\nimport os\n\nasync def main():\n pid = os.fork()\n if pid:\n os.waitpid(pid, 0)\n\nasyncio.run(main())\n```\n\nThe traceback looks like:\n```\nTraceback (most recent call last):\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py\", line 190, in run\n return runner.run(main)\n ^^^^^^^^^^^^^^^^\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py\", line 118, in run\n return self._loop.run_until_complete(task)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 641, in run_until_complete\n self.run_forever()\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 608, in run_forever\n self._run_once()\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 1898, in _run_once\n event_list = self._selector.select(timeout)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/selectors.py\", line 566, in select\n kev_list = self._selector.control(None, max_ev, timeout)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nOSError: [Errno 9] Bad file descriptor\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"~/forkasyncio.py\", line 9, in \u003cmodule\u003e\n asyncio.run(main())\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py\", line 189, in run\n with Runner(debug=debug) as runner:\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py\", line 63, in __exit__\n self.close()\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py\", line 72, in close\n loop.run_until_complete(loop.shutdown_asyncgens())\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 641, in run_until_complete\n self.run_forever()\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 608, in run_forever\n self._run_once()\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py\", line 1898, in _run_once\n event_list = self._selector.select(timeout)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/local/Cellar/python@3.11/3.11.10/Frameworks/Python.framework/Versions/3.11/lib/python3.11/selectors.py\", line 566, in select\n kev_list = self._selector.control(None, max_ev, timeout)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nOSError: [Errno 9] Bad file descriptor\nsys:1: RuntimeWarning: coroutine 'BaseEventLoop.shutdown_asyncgens' was never awaited\n```\n\nI believe the traceback is produced by the child process.\n\nI would not expect bad file descriptor in either the parent or the child because fork is supposed to copy the open file descriptors. I have even tried a custom fork module to ensure `os.fork` isn't closing the file descriptor.\n\nThe issue also happens if the child does `sys.exit()`. I find the best workaround is to have the child do `os._exit(0)`:\n\n```python\nimport asyncio\nimport os\nimport sys\n\nasync def main():\n pid = os.fork()\n if pid:\n os.waitpid(pid, 0)\n else:\n sys.stdout.flush()\n sys.stderr.flush()\n os._exit(0)\n\nasyncio.run(main())\n```\n\nThis produces no traceback. I also avoid doing anything asyncio in the child.\n\nI'm mainly curious about what file descriptor is bad; it doesn't seem possible.\n\nIt sounds like this issue could be fixed by https://github.com/python/cpython/pull/99539, but I still reproduce the issue in 3.12.7 and 3.13.0, though with a slightly different exception:\n```\nTraceback (most recent call last):\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/runners.py\", line 194, in run\n return runner.run(main)\n ^^^^^^^^^^^^^^^^\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/runners.py\", line 118, in run\n return self._loop.run_until_complete(task)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/base_events.py\", line 674, in run_until_complete\n self.run_forever()\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/base_events.py\", line 641, in run_forever\n self._run_once()\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/base_events.py\", line 1948, in _run_once\n event_list = self._selector.select(timeout)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/selectors.py\", line 566, in select\n kev_list = self._selector.control(None, max_ev, timeout)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nValueError: I/O operation on closed kqueue object\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/runners.py\", line 71, in close\n loop.run_until_complete(loop.shutdown_asyncgens())\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/base_events.py\", line 674, in run_until_complete\n self.run_forever()\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/base_events.py\", line 641, in run_forever\n self._run_once()\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/base_events.py\", line 1948, in _run_once\n event_list = self._selector.select(timeout)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/selectors.py\", line 566, in select\n kev_list = self._selector.control(None, max_ev, timeout)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nValueError: I/O operation on closed kqueue object\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"~/forkasyncio.py\", line 10, in \u003cmodule\u003e\n asyncio.run(main())\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/runners.py\", line 193, in run\n with Runner(debug=debug, loop_factory=loop_factory) as runner:\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/runners.py\", line 62, in __exit__\n self.close()\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/runners.py\", line 77, in close\n loop.close()\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/unix_events.py\", line 68, in close\n super().close()\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/selector_events.py\", line 104, in close\n self._close_self_pipe()\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/selector_events.py\", line 111, in _close_self_pipe\n self._remove_reader(self._ssock.fileno())\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/selector_events.py\", line 305, in _remove_reader\n self._selector.unregister(fd)\n File \"/Users/will/.pyenv/versions/3.12.7/lib/python3.12/selectors.py\", line 542, in unregister\n self._selector.control([kev], 0, 0)\nValueError: I/O operation on closed kqueue object\n/Users/will/.pyenv/versions/3.12.7/lib/python3.12/asyncio/base_events.py:712: RuntimeWarning: coroutine 'BaseEventLoop.shutdown_asyncgens' was never awaited\n```\n\n\n\n### CPython versions tested on:\n\n3.11\n\n### Operating systems tested on:\n\nmacOS","author":{"url":"https://github.com/wjmelements","@type":"Person","name":"wjmelements"},"datePublished":"2025-02-22T02:10:19.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3},"url":"https://github.com/130442/cpython/issues/130442"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:c715b432-97a5-edfd-75d4-70779bbfcb83 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E4FE:D1023:C8ED4:1152E3:696963F4 |
| html-safe-nonce | ed3c46d8db101d7d84b8c5a3e7f972111103c241fa34068a6b39dd8e683e2df2 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFNEZFOkQxMDIzOkM4RUQ0OjExNTJFMzo2OTY5NjNGNCIsInZpc2l0b3JfaWQiOiI0NTM5MDE1NzE5MDA4NDI5MDQ0IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 632767d2852ae285ee19e88425bbd8984e997f5c261b4daa3c36e6f2eccc2194 |
| hovercard-subject-tag | issue:2870374436 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/130442/issue_layout |
| twitter:image | https://opengraph.githubassets.com/defeefb6adbf9aafb042b0e3c2fb9e417906448a9aef6cb6506034056f64eb21/python/cpython/issues/130442 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/defeefb6adbf9aafb042b0e3c2fb9e417906448a9aef6cb6506034056f64eb21/python/cpython/issues/130442 |
| og:image:alt | Bug report Bug description: Here is a simple repro: import asyncio import os async def main(): pid = os.fork() if pid: os.waitpid(pid, 0) asyncio.run(main()) The traceback looks like: Traceback (mo... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | wjmelements |
| hostname | github.com |
| expected-hostname | github.com |
| None | 48487c1ad776a7975b7132d95f4240ff3ae37cd5b8e3cb597102a4edb76738f1 |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 669463fcc54773a88c1f5a44eef6b99a5504b9c7 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width