Bug report
Bug description:
While running an asyncio-based service on Windows, I observed the following exception chain:
- ov.getresult() inside asyncio.windows_events.finish_socket_func() raises:
OSError: [WinError 995] The I/O operation has been aborted due to either a thread exit or an application request.
- Then inside _poll() in the same file, this is translated by finish_socket_func() into:
ConnectionResetError: [WinError 995] The I/O operation has been aborted ...
- Then _poll() executes:
f.set_exception(e)
which raises:
asyncio.exceptions.InvalidStateError: invalid state
- This exception then appears on the main event loop path, including frames in:
- asyncio.base_events.BaseEventLoop._run_once()
- asyncio.base_events.BaseEventLoop.run_forever()
- asyncio.base_events.BaseEventLoop.run_until_complete()
- asyncio.runners.Runner.run()
- asyncio.run()
- After InvalidStateError is raised, the service process exits.
———
Environment
- OS: Windows
- Python: 3.13.12
- Relevant stdlib files:
- Lib/asyncio/windows_events.py
- Lib/asyncio/base_events.py
- Lib/asyncio/runners.py
- Lib/asyncio/futures.py
———
Observed traceback
2026-04-24 10:35:08 - ERROR - uvicorn.error - Traceback (most recent call last):
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\windows_events.py", line 463, in finish_socket_func
return ov.getresult()
~~~~~~~~~~~~^^
OSError: [WinError 995] 由于线程退出或应用程序请求,已中止 I/O 操作。
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\windows_events.py", line 804, in _poll
value = callback(transferred, key, ov)
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\windows_events.py", line 467, in finish_socket_func
raise ConnectionResetError(*exc.args)
ConnectionResetError: [WinError 995] 由于线程退出或应用程序请求,已中止 I/O 操作。
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\runners.py", line 195, in run
return runner.run(main)
~~~~~~~~~~^^^^^^
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\runners.py", line 118, in run
return self._loop.run_until_complete(task)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\base_events.py", line 712, in run_until_complete
self.run_forever()
~~~~~~~~~~~~~~~~^^
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\base_events.py", line 683, in run_forever
self._run_once()
~~~~~~~~~~~~~~^^
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\base_events.py", line 2012, in _run_once
event_list = self._selector.select(timeout)
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\windows_events.py", line 446, in select
self._poll(timeout)
~~~~~~~~~~^^^^^^^^^
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\windows_events.py", line 806, in _poll
f.set_exception(e)
~~~~~~~~~~~~~~~^^^
File "C:\Users\moza\AppData\Roaming\uv\python\cpython-3.13.12-windows-x86_64-none\Lib\asyncio\windows_events.py", line 89, in set_exception
super().set_exception(exception)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
asyncio.exceptions.InvalidStateError: invalid state
———
Relevant source code
- Key code in asyncio.windows_events.IocpProactor._poll():
if obj in self._stopped_serving:
f.cancel()
elif not f.done():
try:
value = callback(transferred, key, ov)
except OSError as e:
f.set_exception(e)
self._results.append(f)
else:
f.set_result(value)
self._results.append(f)
- asyncio.futures.Future.done():
def done(self):
return self._state != _PENDING
- asyncio.futures.Future.set_exception():
def set_exception(self, exception):
if self._state != _PENDING:
raise exceptions.InvalidStateError(...)
———
What I would like to confirm
In IocpProactor._poll(), entering:
elif not f.done():
means that, at the time of this check, f should still be PENDING, according to Future.done().
The next call is synchronous:
value = callback(transferred, key, ov)
There is no explicit await here and no obvious Python-level scheduling switch point.
However, the traceback shows that during callback(...), the lower-level ov.getresult() raises WinError 995, which is translated by finish_socket_func() into ConnectionResetError, and then the immediately
following:
f.set_exception(e)
raises:
asyncio.exceptions.InvalidStateError: invalid state
This means that by the time f.set_exception(e) is executed, f is no longer in the PENDING state.
———
Questions
- Is WinError 995 followed by InvalidStateError a known phenomenon?
- Is this exception chain expected behavior for the Windows Proactor event loop?
- In this scenario, is it expected that IocpProactor._poll() allows InvalidStateError to propagate out of the event loop core and ultimately terminate the process?
———
CPython versions tested on:
3.13
Operating systems tested on:
Windows
Bug report
Bug description:
While running an asyncio-based service on Windows, I observed the following exception chain:
OSError: [WinError 995] The I/O operation has been aborted due to either a thread exit or an application request.
ConnectionResetError: [WinError 995] The I/O operation has been aborted ...
f.set_exception(e)
which raises:
asyncio.exceptions.InvalidStateError: invalid state
———
Environment
———
Observed traceback
———
Relevant source code
———
What I would like to confirm
In IocpProactor._poll(), entering:
elif not f.done():
means that, at the time of this check, f should still be PENDING, according to Future.done().
The next call is synchronous:
value = callback(transferred, key, ov)
There is no explicit await here and no obvious Python-level scheduling switch point.
However, the traceback shows that during callback(...), the lower-level ov.getresult() raises WinError 995, which is translated by finish_socket_func() into ConnectionResetError, and then the immediately
following:
f.set_exception(e)
raises:
asyncio.exceptions.InvalidStateError: invalid state
This means that by the time f.set_exception(e) is executed, f is no longer in the PENDING state.
———
Questions
———
CPython versions tested on:
3.13
Operating systems tested on:
Windows