{"record":{"id":"ccafcdbd53c77ae4","repo":"python/cpython","slug":"connection-lost","errorCode":null,"errorMessage":"Connection lost","messagePattern":"Connection lost","errorType":"exception","errorClass":"ConnectionResetError","httpStatus":null,"severity":"error","filePath":"Lib/asyncio/streams.py","lineNumber":166,"sourceCode":"            if not waiter.done():\n                waiter.set_result(None)\n\n    def connection_lost(self, exc):\n        self._connection_lost = True\n        # Wake up the writer(s) if currently paused.\n        if not self._paused:\n            return\n\n        for waiter in self._drain_waiters:\n            if not waiter.done():\n                if exc is None:\n                    waiter.set_result(None)\n                else:\n                    waiter.set_exception(exc)\n\n    async def _drain_helper(self):\n        if self._connection_lost:\n            raise ConnectionResetError('Connection lost')\n        if not self._paused:\n            return\n        waiter = self._loop.create_future()\n        self._drain_waiters.append(waiter)\n        try:\n            await waiter\n        finally:\n            self._drain_waiters.remove(waiter)\n\n    def _get_close_waiter(self, stream):\n        raise NotImplementedError\n\n\nclass StreamReaderProtocol(FlowControlMixin, protocols.Protocol):\n    \"\"\"Helper class to adapt between Protocol and StreamReader.\n\n    (This is a helper class instead of making StreamReader itself a\n    Protocol subclass, because the StreamReader has other potential","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/asyncio/streams.py#L148-L184","documentation":"ConnectionResetError('Connection lost') is raised by StreamWriter.drain() (via FlowControlMixin._drain_helper) when the underlying transport has already flagged _connection_lost. It is asyncio's way of surfacing, at the next await point, that the peer closed or reset the connection after you wrote data. Drain is the only write-path await, so this is where pending connection loss is reported.","triggerScenarios":"Calling await writer.write(...) then await writer.drain() after the transport received connection_lost (peer sent RST/FIN, socket error, or transport.abort() was called); writing after protocol.connection_lost() fired.","commonSituations":"HTTP or RPC clients that keep writing requests after the server closed the idle connection; servers continuing to stream after client disconnect; mobile/flaky networks where the reset arrives mid-request; code that ignores earlier transport errors and keeps using the writer.","solutions":["Treat any earlier transport error/EOF as terminal: stop writing and close the writer instead of continuing the write loop","Check writer.is_closing() before writing/draining and abort if true","Catch ConnectionResetError (and BrokenPipeError) around drain and reconnect/retry at the protocol level","Enable keepalives or heartbeats so a dead connection is detected before you write"],"exampleFix":"// before\nwriter.write(payload)\nawait writer.drain()\n\n// after\nif writer.is_closing():\n    raise ConnectionResetError('local writer already closing')\nwriter.write(payload)\ntry:\n    await writer.drain()\nexcept (ConnectionResetError, BrokenPipeError):\n    writer.close()\n    raise","handlingStrategy":"try-catch","validationCode":"if writer.is_closing():\n    raise ConnectionResetError('writer already closing; do not write')","typeGuard":"null","tryCatchPattern":"try:\n    writer.write(payload)\n    await writer.drain()\nexcept (ConnectionResetError, BrokenPipeError):\n    writer.close()\n    await reconnect_and_resend(payload)  # app-level recovery","preventionTips":["Check writer.is_closing() before every write/drain in long-lived connections","Stop the write loop as soon as protocol.connection_lost() or any transport error fires","Add heartbeats/keepalive so dead peers are detected before the next write"],"tags":["asyncio","network","streams","connection-reset"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}