{"record":{"id":"0a0d98d3ad763b88","repo":"microsoft/aspire","slug":"connection-closed","errorCode":null,"errorMessage":"Connection closed","messagePattern":"Connection closed","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.CodeGeneration.Python/PythonModuleBuilder.cs","lineNumber":906,"sourceCode":"                signal.signal(signal.SIGINT, self._handle_sigint)\n\n                _logger.info(\"Connected to AppHost\")\n\n                # Start receiving messages in a background thread\n                self._receive_thread = threading.Thread(target=self._receive_loop, daemon=True)\n                self._receive_thread.start()\n\n                # Start heartbeat thread to monitor connection health\n                self._heartbeat_thread = threading.Thread(target=self._heartbeat_loop, daemon=True)\n                self._heartbeat_thread.start()\n\n            def _recv_exactly(self, n: int) -> bytes:\n                '''Read exactly n bytes from the socket'''\n                data = b\"\"\n                while len(data) < n:\n                    chunk = typing.cast(_PipeSocket, self._socket).recv(n - len(data))\n                    if not chunk:\n                        raise ConnectionError(\"Connection closed\")\n                    data += chunk\n                return data\n\n            def _read_line(self) -> bytes:\n                '''Read a line ending with \\\\r\\\\n from the socket'''\n                line = b\"\"\n                while True:\n                    byte = typing.cast(_PipeSocket, self._socket).recv(1)\n                    if not byte:\n                        raise ConnectionError(\"Connection closed\")\n                    line += byte\n                    if line.endswith(b\"\\r\\n\"):\n                        return line[:-2]  # Remove \\r\\n\n\n            def _read_headers(self) -> dict[str, str]:\n                '''Read HTTP-style headers until empty line.\n\n                Enforces limits on header count and total size to prevent","sourceCodeStart":888,"sourceCodeEnd":924,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.CodeGeneration.Python/PythonModuleBuilder.cs#L888-L924","documentation":"Raised by _recv_exactly in the generated Python client when the underlying pipe/socket returns an empty chunk before the requested number of bytes has been read. An empty recv means the peer closed the connection, so a complete message can no longer be assembled.","triggerScenarios":"Calling any client method that reads a length-prefixed response after the host has closed or exited; host restarting between request and response; abrupt process kill mid-response.","commonSituations":"AppHost stopped while the client holds an idle connection; host crash mid-request; timeout/kill on the server side for a long-running capability.","solutions":["Catch ConnectionError and re-establish the connection before retrying the operation.","Verify the host process was alive for the duration of the call; inspect host logs for crashes.","Reduce the chance of mid-response disconnects by keeping requests within host-side deadlines.","Treat any in-flight partial message as discarded after reconnect (the protocol has no resume)."],"exampleFix":"// before\nresponse = client.invoke_capability(\"get_items\", args)\n\n// after\ntry:\n    response = client.invoke_capability(\"get_items\", args)\nexcept ConnectionError:\n    client.reconnect()\n    response = client.invoke_capability(\"get_items\", args)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    response = client.invoke_capability(cap, args)\nexcept ConnectionError:\n    client.reconnect()\n    response = client.invoke_capability(cap, args)","preventionTips":["Keep the host alive for the whole client session.","Reconnect after any error instead of reusing a suspect stream.","Monitor host logs for crashes correlating with disconnects."],"tags":["connection-closed","protocol","python","ipc"],"backgroundTag":"broken-pipe","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}