{"record":{"id":"98ba53ab7e144d7b","repo":"aio-libs/aiohttp","slug":"cannot-write-to-closing-transport-98ba53","errorCode":null,"errorMessage":"Cannot write to closing transport","messagePattern":"Cannot write to closing transport","errorType":"exception","errorClass":"ClientConnectionResetError","httpStatus":null,"severity":"error","filePath":"aiohttp/http_writer.py","lineNumber":103,"sourceCode":"        return self._protocol\n\n    def enable_chunking(self) -> None:\n        self.chunked = True\n\n    def enable_compression(\n        self, encoding: str = \"deflate\", strategy: int | None = None\n    ) -> None:\n        self._compress = ZLibCompressor(encoding=encoding, strategy=strategy)\n\n    def _write(\n        self, chunk: Union[bytes, bytearray, \"memoryview[int]\", \"memoryview[bytes]\"]\n    ) -> None:\n        size = len(chunk)\n        self.buffer_size += size\n        self.output_size += size\n        transport = self._protocol.transport\n        if transport is None or transport.is_closing():\n            raise ClientConnectionResetError(\"Cannot write to closing transport\")\n        transport.write(chunk)\n\n    def _writelines(\n        self,\n        chunks: Iterable[\n            Union[bytes, bytearray, \"memoryview[int]\", \"memoryview[bytes]\"]\n        ],\n    ) -> None:\n        size = 0\n        for chunk in chunks:\n            size += len(chunk)\n        self.buffer_size += size\n        self.output_size += size\n        transport = self._protocol.transport\n        if transport is None or transport.is_closing():\n            raise ClientConnectionResetError(\"Cannot write to closing transport\")\n        if SKIP_WRITELINES or size < MIN_PAYLOAD_FOR_WRITELINES:\n            transport.write(b\"\".join(chunks))","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/http_writer.py#L85-L121","documentation":"Raised as ClientConnectionResetError when StreamWriter._write attempts to write a chunk but the underlying transport is None or is closing (transport.is_closing()). The guard runs before every transport.write in the synchronous _write path. It indicates the connection is shutting down and further writes are unsafe.","triggerScenarios":"The server handler (or client writer) calls write()/StreamWriter._write after the transport has started closing — e.g. the peer closed/reset the connection, or write_eof was issued, and a subsequent write is attempted.","commonSituations":"A handler writing a response after the client disconnected (slow client / aborted request); pipelined writes racing with connection close; a write scheduled by a background task after the response finished; keep-alive timeout firing mid-write; the peer sending a RST/FIN.","solutions":["Guard writes: check request.transport.is_closing() (or the writer) before writing, and bail out cleanly.","Catch ClientConnectionResetError / ConnectionResetError around write+drain and treat as a normal client-disconnect.","Avoid background tasks that outlive the response; cancel them on cleanup.","Use drain() and handle CancelledError to stop writing promptly when the client goes away.","For long streams, detect disconnect early (e.g. via disconnector wait) and abort the producer."],"exampleFix":"# before\r\nasync def handler(request):\r\n    while True:\r\n        await request.transport.write(data)  # may raise after client gone\r\n\r\n# after\r\nasync def handler(request):\r\n    try:\r\n        resp = web.StreamResponse()\r\n        await resp.prepare(request)\r\n        while True:\r\n            await resp.write(data)\r\n            await resp.drain()\r\n    except (ClientConnectionResetError, ConnectionResetError):\r\n        return resp  # client gone, stop quietly","handlingStrategy":"try-catch","validationCode":"def can_write(transport) -> bool:\n    return transport is not None and not transport.is_closing()","typeGuard":null,"tryCatchPattern":"from aiohttp import ClientConnectionResetError\n\nasync def safe_write(writer, chunk):\n    try:\n        await writer.write(chunk)\n        await writer.drain()\n    except ClientConnectionResetError:\n        # client disconnected; stop producing\n        return False\n    return True","preventionTips":["Check transport.is_closing() before writing in long-lived handlers.","Catch ClientConnectionResetError around write/drain and stop cleanly.","Cancel producer tasks on disconnect; do not let them outlive the response.","Handle CancelledError to abort writes promptly."],"tags":["http-writer","connection-reset","transport","client-disconnect","writes"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}