{"record":{"id":"2a92cf3c1879035d","repo":"github/copilot-sdk","slug":"request-cancelled-by-runtime","errorCode":null,"errorMessage":"Request cancelled by runtime","messagePattern":"Request cancelled by runtime","errorType":"exception","errorClass":"CancellationException","httpStatus":null,"severity":"warning","filePath":"java/sdk/src/main/java/com/github/copilot/LlmInferenceExchange.java","lineNumber":156,"sourceCode":"        body.add(new BodyItem(ItemKind.CANCEL, null, false));\n    }\n\n    /**\n     * Reads the next request body frame, blocking until one is available.\n     *\n     * @return the next frame, or {@code null} when the body has ended\n     * @throws InterruptedException\n     *             if interrupted while waiting\n     * @throws CancellationException\n     *             if the runtime cancelled the request\n     */\n    BodyFrame readFrame() throws InterruptedException {\n        BodyItem item = body.take();\n        switch (item.kind()) {\n            case CANCEL -> {\n                // Re-arm the sentinel so subsequent reads keep failing fast.\n                body.add(item);\n                throw new CancellationException(\"Request cancelled by runtime\");\n            }\n            case END -> {\n                body.add(item);\n                return null;\n            }\n            default -> {\n                return new BodyFrame(item.data(), item.binary());\n            }\n        }\n    }\n\n    byte[] drainBody() throws InterruptedException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        BodyFrame frame;\n        while ((frame = readFrame()) != null) {\n            out.writeBytes(frame.data());\n        }\n        return out.toByteArray();","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/LlmInferenceExchange.java#L138-L174","documentation":"LlmInferenceExchange.readFrame() consumes items from the response body queue; when it pulls a CANCEL sentinel it re-arms it in the queue (so later reads fail fast too) and throws CancellationException('Request cancelled by runtime'). This signals that the runtime cancelled the LLM inference request while the reader was pumping body frames.","triggerScenarios":"The runtime cancels the inference request (user abort, timeout, client disconnect) while readFrame() — called from pump() or drainBody() — is waiting on or draining the body BlockingQueue (LlmInferenceExchange.java:156).","commonSituations":"User presses stop in a streaming chat UI; the host cancels a long-running generation; a downstream timeout tears down the request mid-stream and the pump loop observes the cancellation sentinel.","solutions":["Treat CancellationException as a normal, expected termination: catch it around the pump/drain loop and clean up without logging as an error.","Stop issuing follow-up work for the request once cancellation is observed — the sentinel is re-armed so reads keep failing fast.","If cancellation is unexpected, trace why the runtime cancelled (timeouts, abort signals) and adjust those policies."],"exampleFix":"// before\nwhile ((frame = exchange.readFrame()) != null) { consume(frame); }\n// after\ntry {\n    while ((frame = exchange.readFrame()) != null) { consume(frame); }\n} catch (CancellationException e) {\n    LOG.fine(\"Inference stream cancelled by runtime\");\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    while ((frame = exchange.readFrame()) != null) { consume(frame); }\n} catch (CancellationException e) {\n    cleanup(); // expected: runtime cancelled the request\n}","preventionTips":["Always handle CancellationException as a normal stream termination path.","Stop downstream processing once cancellation is observed; the sentinel re-arms for fast failure.","Correlate cancellations with abort/timeout sources to distinguish expected from unexpected ones."],"tags":["cancellation","streaming","async"],"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"}