{"record":{"id":"323698eeae6d59bb","repo":"github/copilot-sdk","slug":"copilot-request-was-cancelled-by-the-runtime-323698","errorCode":null,"errorMessage":"Copilot request was cancelled by the runtime.","messagePattern":"Copilot request was cancelled by the runtime\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/copilot/copilot_request_handler.py","lineNumber":456,"sourceCode":"        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,\n                status_text=status_text,\n            )\n        )\n\n    async def write_response(self, data: str | bytes) -> None:\n        if self.cancelled:\n            raise RuntimeError(\"Copilot request was cancelled by the runtime.\")\n        if not self.started:\n            raise RuntimeError(\"Copilot request response write() called before start().\")\n        if self.finished:\n            raise RuntimeError(\"Copilot request response write() called after end()/error().\")\n        if isinstance(data, bytes):\n            payload = base64.b64encode(data).decode(\"ascii\")\n            is_binary = True\n        else:\n            payload = data\n            is_binary = False\n        await self._require_rpc().http_response_chunk(\n            LlmInferenceHTTPResponseChunkRequest(\n                data=payload,\n                request_id=self.request_id,\n                binary=is_binary or None,\n                end=False,\n            )\n        )","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/copilot_request_handler.py#L438-L474","documentation":"write_response() refuses to write body data once the runtime has cancelled the Copilot request (the `cancelled` flag was set via the cancellation path). Continuing to write would stream bytes to a request_id the client/runtime has abandoned. The library raises immediately so the handler can stop producing output.","triggerScenarios":"The runtime cancelled the request (client disconnect, timeout, explicit cancel) and the handler subsequently calls write_response(); long-running generation continues streaming after a cancel notification arrives.","commonSituations":"User closes the connection or hits stop mid-generation while a model callback keeps streaming; timeouts in the runtime cancelling the exchange while the handler loop is mid-chunk.","solutions":["Check `response.cancelled` before each write (or wrap writes in try/except RuntimeError and break the stream loop).","Stop generation as soon as cancellation is observed; do not attempt further writes or end_response().","Register a cancellation callback that terminates the upstream model stream so writes never happen post-cancel."],"exampleFix":"// before\nfor chunk in model_stream:\n    await response.write_response(chunk)\n\n// after\nfor chunk in model_stream:\n    if response.cancelled:\n        break\n    try:\n        await response.write_response(chunk)\n    except RuntimeError:\n        break","handlingStrategy":"try-catch","validationCode":"if response.cancelled:\n    stop_generation()\n    return","typeGuard":"def is_writable(response) -> bool:\n    return not response.cancelled and response.started and not response.finished","tryCatchPattern":"try:\n    await response.write_response(chunk)\nexcept RuntimeError as e:\n    if \"cancelled by the runtime\" in str(e):\n        break  # client/runtime gone; stop streaming\n    raise","preventionTips":["Check `cancelled` before every write in streaming loops.","Wire cancellation into the upstream generator so it stops producing immediately.","Never treat post-cancel writes as recoverable; abort the stream."],"tags":["cancellation","streaming","python","copilot"],"backgroundTag":"request-cancelled","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"}