Bug report
Bug description:
Closing a datagram transport that still has datagrams queued drops them and
never calls connection_lost(), so the socket is closed only by __del__,
with a ResourceWarning; SelectorEventLoop flushes them and tears down
normally. _ProactorDatagramTransport._loop_writing() returns at
if self._conn_lost: return, which close() has just incremented, so the
teardown branch below it -- the one close() deliberately leaves to the
write loop when the buffer is non-empty -- is unreachable.
Reproducer
import asyncio
import sys
async def main():
loop = asyncio.get_running_loop()
print(sys.version)
print(type(loop).__name__)
received = []
lost = loop.create_future()
class Receiver(asyncio.DatagramProtocol):
def datagram_received(self, data, addr):
received.append(data)
class Sender(asyncio.DatagramProtocol):
def connection_lost(self, exc):
if not lost.done():
lost.set_result(exc)
recv_transport, _ = await loop.create_datagram_endpoint(
Receiver, local_addr=('127.0.0.1', 0))
addr = recv_transport.get_extra_info('sockname')
transport, _ = await loop.create_datagram_endpoint(
Sender, remote_addr=addr)
for i in range(5):
transport.sendto(b'datagram-%d' % i)
transport.close()
try:
await asyncio.wait_for(lost, 5)
except TimeoutError:
print('connection_lost(): never called')
else:
print('connection_lost(): called')
await asyncio.sleep(0.5)
print('datagrams received:', len(received))
print('write buffer size: ', transport.get_write_buffer_size())
recv_transport.close()
await asyncio.sleep(0)
asyncio.run(main(), loop_factory=asyncio.SelectorEventLoop)
asyncio.run(main(), loop_factory=asyncio.ProactorEventLoop)
Output on Windows:
PS C:\Users\tagra\projects\cpython> py -3.14 .\reproducer.py
3.14.7 (tags/v3.14.7:823f032, Aug 5 2026, 10:51:32) [MSC v.1944 64 bit (AMD64)]
_WindowsSelectorEventLoop
connection_lost(): called
datagrams received: 5
write buffer size: 0
3.14.7 (tags/v3.14.7:823f032, Aug 5 2026, 10:51:32) [MSC v.1944 64 bit (AMD64)]
ProactorEventLoop
connection_lost(): never called
datagrams received: 1
write buffer size: 72
PS C:\Users\tagra\projects\cpython> py -3.13 .\reproducer.py
3.13.15 (tags/v3.13.15:4061bc4, Aug 5 2026, 13:05:39) [MSC v.1944 64 bit (AMD64)]
_WindowsSelectorEventLoop
connection_lost(): called
datagrams received: 5
write buffer size: 0
3.13.15 (tags/v3.13.15:4061bc4, Aug 5 2026, 13:05:39) [MSC v.1944 64 bit (AMD64)]
ProactorEventLoop
connection_lost(): never called
datagrams received: 1
write buffer size: 72
CPython versions tested on
Py3.13 Py3.14
Operating systems tested on
Windows
CPython versions tested on:
3.13, 3.14
Operating systems tested on:
Windows
Linked PRs
Bug report
Bug description:
Closing a datagram transport that still has datagrams queued drops them and
never calls
connection_lost(), so the socket is closed only by__del__,with a
ResourceWarning;SelectorEventLoopflushes them and tears downnormally.
_ProactorDatagramTransport._loop_writing()returns atif self._conn_lost: return, whichclose()has just incremented, so theteardown branch below it -- the one
close()deliberately leaves to thewrite loop when the buffer is non-empty -- is unreachable.
Reproducer
Output on Windows:
CPython versions tested on
Py3.13 Py3.14
Operating systems tested on
Windows
CPython versions tested on:
3.13, 3.14
Operating systems tested on:
Windows
Linked PRs