python/cpython · error · RuntimeError
Transport is closing
Error message
Transport is closing
What it means
A RuntimeError raised by loop.sendfile() when the transport passed in is already closing. sendfile enqueues bytes on a live transport; once is_closing() is true the transport will never write again (peer closed, protocol aborted, or transport.close() was called), so asyncio refuses with RuntimeError instead of silently dropping the file.
Source
Thrown at Lib/asyncio/base_events.py:1276
file must be a regular file object opened in binary mode.
offset tells from where to start reading the file. If specified,
count is the total number of bytes to transmit as opposed to
sending the file until EOF is reached. File position is updated on
return or also in case of error in which case file.tell()
can be used to figure out the number of bytes
which were sent.
fallback set to True makes asyncio to manually read and send
the file when the platform does not support the sendfile syscall
(e.g. Windows or SSL socket on Unix).
Raise SendfileNotAvailableError if the system does not support
sendfile syscall and fallback is False.
"""
if transport.is_closing():
raise RuntimeError("Transport is closing")
mode = getattr(transport, '_sendfile_compatible',
constants._SendfileMode.UNSUPPORTED)
if mode is constants._SendfileMode.UNSUPPORTED:
raise RuntimeError(
f"sendfile is not supported for transport {transport!r}")
if mode is constants._SendfileMode.TRY_NATIVE:
try:
return await self._sendfile_native(transport, file,
offset, count)
except exceptions.SendfileNotAvailableError:
if not fallback:
raise
if not fallback:
raise exceptions.SendfileNotAvailableError(
f"fallback is disabled and native sendfile is not "
f"supported for transport {transport!r}")
return await self._sendfile_fallback(transport, file,View on GitHub (pinned to bc6749cc3b)
Solutions
- Track connection state in your protocol (set a flag in connection_lost) and skip/cancel pending sendfile tasks.
- Await the sendfile in a try/except RuntimeError and treat it as a normal disconnect, not a bug.
- Cancel outstanding sendfile tasks during shutdown before closing the transport.
Example fix
// before
async def stream_file(transport, path):
with open(path, 'rb') as f:
await loop.sendfile(transport, f) # may race client disconnect
// after
async def stream_file(transport, path):
with open(path, 'rb') as f:
try:
await loop.sendfile(transport, f)
except RuntimeError:
log('peer disconnected during transfer') Defensive patterns
Strategy: try-catch
Validate before calling
if transport.is_closing():
log.info('skipping sendfile: transport is closing')
return 0 Try / catch
try:
sent = await loop.sendfile(transport, f, offset, count)
except RuntimeError as e:
if 'Transport is closing' not in str(e):
raise
log.info('peer disconnected during sendfile')
sent = 0 Prevention
- Set a 'lost' flag in Protocol.connection_lost and check it before each sendfile.
- Cancel pending file-transfer tasks during server shutdown before closing transports.
- Treat sendfile RuntimeError as a normal disconnect path, not an exceptional bug.
When it happens
Trigger: Awaiting loop.sendfile(transport, f, offset, count) after transport.close(), after connection_lost fired (peer reset), or in a protocol callback that runs while shutdown is in progress (e.g. inside ConnectionLost handling).
Common situations: Servers that stream files and race client disconnects: the client goes away, connection_lost fires, but a queued sendfile task still runs; graceful-shutdown handlers that try to flush a file through a closing transport.
Related errors
- Failed to fetch glossary.json
- d3-flame-graph library failed to load
- sendfile is not supported for transport {transport!r}
- unable to write; sendfile is in progress
- BUILD_GNU_TYPE is not defined
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/06f12eb8c06f0cc8.
Report an issue: GitHub.