{"record":{"id":"034da230e2c72f94","repo":"github/copilot-sdk","slug":"request-cancelled-by-runtime-034da2","errorCode":null,"errorMessage":"Request cancelled by runtime","messagePattern":"Request cancelled by runtime","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"python/copilot/copilot_request_handler.py","lineNumber":690,"sourceCode":"    \"\"\"Run ``coro`` but abort it (and raise) when ``cancel_event`` fires.\"\"\"\n    task = asyncio.ensure_future(coro)\n    waiter = asyncio.ensure_future(cancel_event.wait())\n    try:\n        done, _ = await asyncio.wait({task, waiter}, return_when=asyncio.FIRST_COMPLETED)\n        if task in done:\n            exc = task.exception()\n            if exc is not None:\n                raise exc\n            return\n        # Cancellation fired first.\n        task.cancel()\n        try:\n            await task\n        except (asyncio.CancelledError, Exception):\n            # The awaited task was cancelled; its unwind exception is expected\n            # and irrelevant — we raise the cancellation result below.\n            pass\n        raise RuntimeError(\"Request cancelled by runtime\")\n    finally:\n        if not waiter.done():\n            waiter.cancel()\n\n\nasync def _build_httpx_request(exchange: _CopilotRequestExchange) -> httpx.Request:\n    import httpx\n\n    header_pairs = [\n        (name, value)\n        for name, values in exchange.headers.items()\n        if name.lower() not in _FORBIDDEN_REQUEST_HEADERS\n        for value in (values or [])\n    ]\n    method = exchange.method.upper()\n    has_body = method not in (\"GET\", \"HEAD\")\n    body = await _drain_async(exchange.request_body)\n    content = body if (has_body and body) else None","sourceCodeStart":672,"sourceCodeEnd":708,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/copilot_request_handler.py#L672-L708","documentation":"_run_cancellable supervises the request task against a cancellation signal: when the cancellation waiter fires, it awaits (and discards) the task's unwind, then unconditionally raises this RuntimeError to abort the HTTP handling flow. It converts a runtime-initiated cancellation into an exception the caller can observe and report.","triggerScenarios":"The runtime's cancellation signal fires while _handle_http is executing — the client aborted the request, the runtime timed it out, or the session was shut down — and the supervised task was cancelled via the waiter mechanism.","commonSituations":"Client disconnects mid-request; runtime-imposed request deadlines; shutdown of the Copilot extension while an HTTP exchange is in flight.","solutions":["Treat this RuntimeError as an expected cancellation outcome: catch it around the request invocation and log/skip rather than retrying.","Check cancellation state before starting expensive work inside the handler so work stops early.","If it fires spuriously, verify the runtime's cancellation conditions (timeouts, client lifetime) in configuration."],"exampleFix":"// before\nawait _run_cancellable(handler_task, cancel_waiter)\n\n// after\ntry:\n    await _run_cancellable(handler_task, cancel_waiter)\nexcept RuntimeError as e:\n    if \"Request cancelled by runtime\" in str(e):\n        logger.info(\"request cancelled by runtime; aborting\")\n    else:\n        raise","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    await _run_cancellable(task, cancel_waiter)\nexcept RuntimeError as e:\n    if str(e) == \"Request cancelled by runtime\":\n        return  # expected cancellation path\n    raise","preventionTips":["Treat this exception as a normal cancellation outcome, not a bug.","Check cancellation signals before starting long work in handlers.","Log cancellations at info level to distinguish them from real failures."],"tags":["cancellation","asyncio","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"}