{"record":{"id":"06f12eb8c06f0cc8","repo":"python/cpython","slug":"transport-is-closing","errorCode":null,"errorMessage":"Transport is closing","messagePattern":"Transport is closing","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/base_events.py","lineNumber":1276,"sourceCode":"\n        file must be a regular file object opened in binary mode.\n\n        offset tells from where to start reading the file. If specified,\n        count is the total number of bytes to transmit as opposed to\n        sending the file until EOF is reached. File position is updated on\n        return or also in case of error in which case file.tell()\n        can be used to figure out the number of bytes\n        which were sent.\n\n        fallback set to True makes asyncio to manually read and send\n        the file when the platform does not support the sendfile syscall\n        (e.g. Windows or SSL socket on Unix).\n\n        Raise SendfileNotAvailableError if the system does not support\n        sendfile syscall and fallback is False.\n        \"\"\"\n        if transport.is_closing():\n            raise RuntimeError(\"Transport is closing\")\n        mode = getattr(transport, '_sendfile_compatible',\n                       constants._SendfileMode.UNSUPPORTED)\n        if mode is constants._SendfileMode.UNSUPPORTED:\n            raise RuntimeError(\n                f\"sendfile is not supported for transport {transport!r}\")\n        if mode is constants._SendfileMode.TRY_NATIVE:\n            try:\n                return await self._sendfile_native(transport, file,\n                                                   offset, count)\n            except exceptions.SendfileNotAvailableError:\n                if not fallback:\n                    raise\n\n        if not fallback:\n            raise exceptions.SendfileNotAvailableError(\n                f\"fallback is disabled and native sendfile is not \"\n                f\"supported for transport {transport!r}\")\n        return await self._sendfile_fallback(transport, file,","sourceCodeStart":1258,"sourceCodeEnd":1294,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/base_events.py#L1258-L1294","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nasync def stream_file(transport, path):\n    with open(path, 'rb') as f:\n        await loop.sendfile(transport, f)  # may race client disconnect\n\n// after\nasync def stream_file(transport, path):\n    with open(path, 'rb') as f:\n        try:\n            await loop.sendfile(transport, f)\n        except RuntimeError:\n            log('peer disconnected during transfer')","handlingStrategy":"try-catch","validationCode":"if transport.is_closing():\n    log.info('skipping sendfile: transport is closing')\n    return 0","typeGuard":null,"tryCatchPattern":"try:\n    sent = await loop.sendfile(transport, f, offset, count)\nexcept RuntimeError as e:\n    if 'Transport is closing' not in str(e):\n        raise\n    log.info('peer disconnected during sendfile')\n    sent = 0","preventionTips":["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."],"tags":["asyncio","sendfile","transport","shutdown","race-condition"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}