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 proactor server leaks the accepted socket and stops accepting when transport creation fails #156365
On the proactor event loop (the default on Windows), BaseProactorEventLoop._start_serving()'s loop() callback runs protocol_factory() and transport creation in the same callback that re-arms accept(), guarded only by except OSError / except CancelledError. When protocol_factory() or _make_ssl_transport() / _make_socket_transport() raises for an accepted connection:
a non-OSError (e.g. a failing protocol_factory) propagates out of loop(): the accepted socket is never closed (it leaks until garbage collection) and accept is not re-armed, so the server stops accepting new connections;
an OSError is caught as 'Accept failed on a socket', which closes the listening socket, and still leaks the accepted socket.
This is the proactor counterpart of gh-155934 (selector accept) and gh-153133 (create_connection): an accepted socket must be closed when the transport is never created, and a per-connection failure must not tear down the listening socket or the accept loop.
Verified with mock-based tests in test_proactor_events (the same approach used for the selector fix in gh-155934), which run on all platforms.
A related case on the same path: accept() itself failing with a transient OSError also closes the listening socket for good.
On the proactor event loop, BaseProactorEventLoop._start_serving() handles any OSError from self._proactor.accept(sock) (or from f.result()) by calling the exception handler ("Accept failed on a socket") and then sock.close() on the listening socket. When the error is transient, such as WinError 10055 (WSAENOBUFS, "the system lacked sufficient buffer space or because a queue was full"), which a Windows host can return briefly under memory pressure, the server never accepts again: the process stays alive and keeps running its other work, but the port refuses every new connection. We hit this on a long-running aiohttp server on a machine under heavy memory pressure.
Seen on CPython 3.12.10 and 3.14.3 (Windows, default proactor loop); the code path is the same in both.
Minimal repro (Windows; injects one WinError 10055 from accept, then tries a client connection):
handler: Accept failed on a socket
connection refused after one transient accept error: [WinError 1225] The remote computer refused the network connection
Retrying after a short backoff instead of closing the socket (keeping the sock.fileno() == -1 case as is) keeps the server alive in this repro. Related: gh-93821 (ERROR_NETNAME_DELETED closing the serving socket).
Activity
Chris0Jeky commentedon Nov 5, 2026
A related case on the same path:
accept()itself failing with a transientOSErroralso closes the listening socket for good.On the proactor event loop,
BaseProactorEventLoop._start_serving()handles anyOSErrorfromself._proactor.accept(sock)(or fromf.result()) by calling the exception handler ("Accept failed on a socket") and thensock.close()on the listening socket. When the error is transient, such asWinError 10055(WSAENOBUFS, "the system lacked sufficient buffer space or because a queue was full"), which a Windows host can return briefly under memory pressure, the server never accepts again: the process stays alive and keeps running its other work, but the port refuses every new connection. We hit this on a long-running aiohttp server on a machine under heavy memory pressure.Seen on CPython 3.12.10 and 3.14.3 (Windows, default proactor loop); the code path is the same in both.
Minimal repro (Windows; injects one
WinError 10055fromaccept, then tries a client connection):Output on 3.12.10:
Retrying after a short backoff instead of closing the socket (keeping the
sock.fileno() == -1case as is) keeps the server alive in this repro. Related: gh-93821 (ERROR_NETNAME_DELETEDclosing the serving socket).Merge branch 'main' into pythongh-156365-proactor-accept-transport-error