{"record":{"id":"cfdadfecb8ff7248","repo":"python/cpython","slug":"unable-to-write-sendfile-is-in-progress-cfdadf","errorCode":null,"errorMessage":"unable to write; sendfile is in progress","messagePattern":"unable to write; sendfile is in progress","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/selector_events.py","lineNumber":1068,"sourceCode":"                exc, 'Fatal error: protocol.eof_received() call failed.')\n            return\n\n        if keep_open:\n            # We're keeping the connection open so the\n            # protocol can write more, but we still can't\n            # receive more, so remove the reader callback.\n            self._loop._remove_reader(self._sock_fd)\n        else:\n            self.close()\n\n    def write(self, data):\n        if not isinstance(data, (bytes, bytearray, memoryview)):\n            raise TypeError(f'data argument must be a bytes, bytearray, or memoryview '\n                            f'object, not {type(data).__name__!r}')\n        if self._eof:\n            raise RuntimeError('Cannot call write() after write_eof()')\n        if self._empty_waiter is not None:\n            raise RuntimeError('unable to write; sendfile is in progress')\n        if not data:\n            return\n\n        if self._conn_lost:\n            if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:\n                logger.warning('socket.send() raised exception.')\n            self._conn_lost += 1\n            return\n\n        if not self._buffer:\n            # Optimization: try to send now.\n            try:\n                n = self._sock.send(data)\n            except (BlockingIOError, InterruptedError):\n                pass\n            except (SystemExit, KeyboardInterrupt):\n                raise\n            except BaseException as exc:","sourceCodeStart":1050,"sourceCodeEnd":1086,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/selector_events.py#L1050-L1086","documentation":"Raised by _SelectorSocketTransport.write() as RuntimeError when a sendfile operation is in progress on the transport. During sendfile the transport sets _empty_waiter (an internal future awaiting an empty write buffer); concurrent write() calls are forbidden because they would corrupt the buffer state the sendfile completion logic depends on.","triggerScenarios":"Calling transport.write(data) (directly or via StreamWriter) while a loop.sendfile(transport, file) / StreamWriter.sendfile() call on the same transport is still awaiting.","commonSituations":"A server handler serving a file with sendfile while a heartbeat/keepalive task writes to the same connection; concurrent tasks sharing one StreamWriter where one sends files; protocols that interleave control frames with large file transfers.","solutions":["Await the sendfile() call to completion before issuing any write() on that transport.","Serialize access to the transport with an asyncio.Lock around sendfile/write sequences.","If interleaving is required, avoid sendfile and stream the file with read()+write() instead (setbufsize / fallback mode).","Cancel or pause background writer tasks for the duration of the sendfile."],"exampleFix":"// before\nsendfile_task = asyncio.create_task(loop.sendfile(transport, f))\ntransport.write(b\"next request?\\n\")  # RuntimeError\n\n// after\nawait loop.sendfile(transport, f)\ntransport.write(b\"next request?\\n\")","handlingStrategy":"validation","validationCode":"conn_lock = asyncio.Lock()\n\nasync def send_file_then_write(transport, path, extra):\n    async with conn_lock:\n        with open(path, 'rb') as f:\n            await loop.sendfile(transport, f)\n        transport.write(extra)  # only after sendfile resolves","typeGuard":null,"tryCatchPattern":"try:\n    transport.write(data)\nexcept RuntimeError as e:\n    if 'sendfile is in progress' in str(e):\n        await sendfile_task  # wait, then retry once\n        transport.write(data)\n    else:\n        raise","preventionTips":["Never let heartbeat/keepalive tasks write while sendfile is active; pause them.","Serialize transport access with a per-connection asyncio.Lock.","If writes must interleave file data, stream with read()+write() instead of sendfile."],"tags":["asyncio","networking","sendfile","concurrency","transport"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}