{"record":{"id":"8430bdb7f6325de2","repo":"github/copilot-sdk","slug":"copilot-request-response-used-after-rpc-connection-8430bd","errorCode":null,"errorMessage":"Copilot request response used after RPC connection closed.","messagePattern":"Copilot request response used after RPC connection closed\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/copilot/copilot_request_handler.py","lineNumber":431,"sourceCode":"        \"\"\"Fill in the request context once the matching start frame arrives.\"\"\"\n        self.session_id = params.session_id\n        self.agent_id = params.agent_id\n        self.parent_agent_id = params.parent_agent_id\n        self.interaction_type = params.interaction_type\n        self.method = params.method\n        self.url = params.url\n        self.headers = params.headers\n        transport = params.transport\n        self.transport = transport.value if transport is not None else \"http\"\n\n    @property\n    def request_body(self) -> _BodyQueue:\n        return self._queue\n\n    def _require_rpc(self) -> ServerLlmInferenceApi:\n        rpc = self._get_server_rpc()\n        if rpc is None:\n            raise RuntimeError(\"Copilot request response used after RPC connection closed.\")\n        return rpc\n\n    async def start_response(\n        self,\n        status: int,\n        status_text: str | None = None,\n        headers: LlmInferenceHeaders | None = None,\n    ) -> None:\n        if self.started:\n            raise RuntimeError(\"Copilot request response start() called twice.\")\n        if self.finished:\n            raise RuntimeError(\"Copilot request response already finished.\")\n        self.started = True\n        await self._require_rpc().http_response_start(\n            LlmInferenceHTTPResponseStartRequest(\n                headers=headers or {},\n                request_id=self.request_id,\n                status=status,","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/copilot_request_handler.py#L413-L449","documentation":"_require_rpc fetches the ServerLlmInferenceApi RPC channel backing the response object; if the connection has been closed the channel is None. Any response use after that point (start_response, write_response, end_response, error_response) raises RuntimeError because responses can no longer be delivered over the dead RPC connection.","triggerScenarios":"Calling start_response/write_response/end_response/error_response after the underlying RPC connection to the Copilot server has closed — e.g. the handler finishes after disconnect, or the response is stored and used later.","commonSituations":"Responding to a request after the client/server connection dropped, holding response objects across reconnects, slow response writing that outlives the connection, or shutdown racing with response generation.","solutions":["Check connection state (or wrap calls in try/except RuntimeError) before using the response object","Complete all response writes while the RPC connection is alive; buffer and resend across a new connection if needed","Treat connection-closed during response as terminal: discard the response and let the client retry the request","Keep a reconnect mechanism and re-issue the whole request rather than reusing the stale response object"],"exampleFix":"// before\nawait response.start_response(200)  # raises after disconnect\n// after\ntry:\n    await response.start_response(200)\n    await response.write_response(data)\n    await response.end_response()\nexcept RuntimeError as e:\n    if \"RPC connection closed\" in str(e):\n        logger.warning(\"dropped response: connection closed\")","handlingStrategy":"try-catch","validationCode":"def can_respond(response) -> bool:\n    try:\n        return response._get_server_rpc() is not None\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    await response.start_response(200)\n    await response.write_response(data)\n    await response.end_response()\nexcept RuntimeError as e:\n    if \"RPC connection closed\" in str(e):\n        logger.warning(\"response aborted: RPC closed\")\n    else:\n        raise","preventionTips":["Finish all response writes before the connection can close","Never cache response objects across reconnects","Monitor connection state and abort response generation on disconnect","Retry by re-issuing the full request on a fresh connection"],"tags":["rpc","connection-closed","lifecycle","response"],"backgroundTag":"broken-pipe","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}