{"record":{"id":"2e3909341ffb6a6b","repo":"github/copilot-sdk","slug":"request-cancelled-by-runtime-item-cancel-reason-2e3909","errorCode":null,"errorMessage":"Request cancelled by runtime: {item.cancel_reason}","messagePattern":"Request cancelled by runtime: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"python/copilot/copilot_request_handler.py","lineNumber":374,"sourceCode":"\n    def push(self, item: _BodyItem) -> None:\n        self._queue.put_nowait(item)\n\n    def __aiter__(self) -> AsyncIterator[bytes]:\n        return self\n\n    async def __anext__(self) -> bytes:\n        if self._done:\n            raise StopAsyncIteration\n        item = await self._queue.get()\n        if item.cancel:\n            self._done = True\n            reason = (\n                f\"Request cancelled by runtime: {item.cancel_reason}\"\n                if item.cancel_reason\n                else \"Request cancelled by runtime\"\n            )\n            raise RuntimeError(reason)\n        if item.end:\n            self._done = True\n            raise StopAsyncIteration\n        return item.chunk if item.chunk is not None else b\"\"\n\n\nclass _CopilotRequestExchange:\n    \"\"\"One intercepted request in flight.\n\n    Carries the request body stream the runtime feeds via ``httpRequestChunk``\n    frames, and emits the handler's response directly to the runtime through\n    the generated ``llmInference`` RPC. Replaces the former provider / sink /\n    response-channel indirection with a single object the adapter owns.\n    \"\"\"\n\n    def __init__(\n        self,\n        request_id: str,","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/copilot_request_handler.py#L356-L392","documentation":"During async iteration of the model response stream (__anext__), the runtime delivered a cancellation item. The handler converts it into a RuntimeError carrying the runtime-provided cancel_reason (or a generic message when none is given). Iteration cannot continue after this point.","triggerScenarios":"The Copilot runtime cancels an in-flight streaming request — e.g. user aborts, upstream timeout, or the server cancels the turn — and the cancel item reaches __anext__ with (or without) a cancel_reason.","commonSituations":"User pressing stop in an IDE/chat UI, long-running prompts killed by server-side limits, network drop causing the runtime to cancel, or client shutdown mid-stream.","solutions":["Catch RuntimeError around the async-for loop and treat it as a normal cancellation, not a bug","Inspect the cancel_reason embedded in the message to decide whether to retry or surface to the user","Stop consuming the iterator after cancellation; set self._done semantics hold — a fresh request is needed","Implement retry with backoff for transient cancellation causes like timeouts"],"exampleFix":"// before\ntext = \"\"\nasync for chunk in response:\n    text += chunk\n// after\ntext = \"\"\ntry:\n    async for chunk in response:\n        text += chunk\nexcept RuntimeError as e:\n    if \"Request cancelled by runtime\" in str(e):\n        text = None  # handle cancellation gracefully","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    async for chunk in response:\n        process(chunk)\nexcept RuntimeError as e:\n    if str(e).startswith(\"Request cancelled by runtime\"):\n        handle_cancel(reason=str(e).partition(\": \")[2])\n    else:\n        raise","preventionTips":["Treat RuntimeError during streaming as cancellation, not a defect","Parse the cancel_reason to decide retry vs. surface-to-user","Never reuse a stream after cancellation; start a new request","Add retry-with-backoff for transient causes like timeouts"],"tags":["cancellation","streaming","runtime","async-iterator"],"backgroundTag":"request-timeout","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"}