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
The fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behaviour calling error_received and continuing to run the Transport #156784
changed the title [-]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior raising the exception and continuing to run the Transport[/-][+]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior calling error_recieved and continuing to run the Transport[/+]on Sep 1, 2026
"""Demonstrates that sending a UDP datagram to a port that isn'tlistening now surfaces a recoverable error consistently on bothSelectorEventLoop and ProactorEventLoop (see gh-91227, gh-127057): - DatagramProtocol.error_received() is called, and the transport keeps working afterwards instead of the read loop dying silently.Windows only. Run with: python snippet.py"""importasyncioimportsocketclassEchoProtocol(asyncio.DatagramProtocol):
defconnection_made(self, transport):
self.transport=transportself.received= []
self.errors= []
defdatagram_received(self, data, addr):
self.received.append(data)
deferror_received(self, exc):
self.errors.append(exc)
defclosed_socket_address():
"""Bind and immediately close a UDP socket to get an address that is guaranteed not to be listening."""sock=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('127.0.0.1', 0))
addr=sock.getsockname()
sock.close()
returnaddrasyncdefdemo_transport(loop):
print('--- DatagramProtocol.error_received() ---')
sock=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(False)
sock.bind(('127.0.0.1', 0))
own_addr=sock.getsockname()
transport, protocol=awaitloop.create_datagram_endpoint(
EchoProtocol, sock=sock)
transport.sendto(b'ping', closed_socket_address())
for_inrange(100):
awaitasyncio.sleep(0.05)
ifprotocol.errors:
breakifprotocol.errors:
print(f'error_received() fired: {protocol.errors[0]!r}')
else:
print('error_received() did NOT fire (timed out waiting)')
# The transport must still work afterwards.transport.sendto(b'still alive', own_addr)
for_inrange(100):
awaitasyncio.sleep(0.05)
ifprotocol.received:
breakprint(f'transport still usable afterwards: {protocol.received!r}')
transport.close()
asyncdefmain(loop):
awaitdemo_transport(loop)
defrun(name, loop):
print(f'\n=== {name} ===')
try:
loop.run_until_complete(main(loop))
finally:
loop.close()
if__name__=='__main__':
run('SelectorEventLoop', asyncio.SelectorEventLoop())
run('ProactorEventLoop', asyncio.ProactorEventLoop())
on 3.14 it reports:
PS C:\Users\tagra\projects\cpython> py -3.14 .\snippet.py
=== SelectorEventLoop ===
--- DatagramProtocol.error_received() ---
error_received() fired: ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None)
transport still usable afterwards: [b'still alive']
=== ProactorEventLoop ===
--- DatagramProtocol.error_received() ---
error_received() did NOT fire (timed out waiting)
transport still usable afterwards: [b'still alive']
on my patched branch I get:
PS C:\Users\tagra\projects\cpython> ./PCbuild/amd64/python_d.exe snippet.py
=== SelectorEventLoop ===
--- DatagramProtocol.error_received() ---
error_received() fired: ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None)
transport still usable afterwards: [b'still alive']
=== ProactorEventLoop ===
--- DatagramProtocol.error_received() ---
error_received() fired: ConnectionResetError(22, 'No service is operating at the destination network endpoint on the remote system', None, 1234, None)
transport still usable afterwards: [b'still alive']
changed the title [-]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior calling error_recieved and continuing to run the Transport[/-][+]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior calling error_received and continuing to run the Transport[/+]on Sep 1, 2026
changed the title [-]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior calling error_received and continuing to run the Transport[/-][+]The fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behaviour calling error_received and continuing to run the Transport[/+]on Sep 1, 2026
Activity
[-]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior raising the exception and continuing to run the Transport[/-][+]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior calling error_recieved and continuing to run the Transport[/+]graingert commentedon Sep 1, 2026
on 3.14 it reports:
on my patched branch I get:
[-]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior calling error_recieved and continuing to run the Transport[/-][+]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior calling error_received and continuing to run the Transport[/+][-]This fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behavior calling error_received and continuing to run the Transport[/-][+]The fix in gh-91227 is incorrect, the SelectorEventLoop has the correct behaviour calling error_received and continuing to run the Transport[/+]graingert commentedon Sep 16, 2026
@kumaraditya303 this isn't fixed yet, so I re-opened it