{"record":{"id":"d7b945b165a707e7","repo":"github/copilot-sdk","slug":"interrupted-while-waiting-for-callback-data","errorCode":null,"errorMessage":"Interrupted while waiting for callback data","messagePattern":"Interrupted while waiting for callback data","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/ffi/QueueInputStream.java","lineNumber":85,"sourceCode":"    public int read(byte[] b, int off, int len) throws IOException {\n        Objects.requireNonNull(b, \"buffer must not be null\");\n        if (off < 0 || len < 0 || off + len > b.length) {\n            throw new IndexOutOfBoundsException(\"Invalid off/len for buffer of length \" + b.length);\n        }\n        if (len == 0) {\n            return 0;\n        }\n        if (eof) {\n            return -1;\n        }\n\n        while (currentChunk == null || currentOffset >= currentChunk.length) {\n            byte[] next;\n            try {\n                next = queue.take();\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                throw new IOException(\"Interrupted while waiting for callback data\", e);\n            }\n            if (next == EOF_SENTINEL) {\n                eof = true;\n                return -1;\n            }\n            if (next.length == 0) {\n                continue;\n            }\n            currentChunk = next;\n            currentOffset = 0;\n        }\n\n        int available = currentChunk.length - currentOffset;\n        int toCopy = Math.min(available, len);\n        System.arraycopy(currentChunk, currentOffset, b, off, toCopy);\n        currentOffset += toCopy;\n        return toCopy;\n    }","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/ffi/QueueInputStream.java#L67-L103","documentation":"QueueInputStream backs its blocking read with a LinkedBlockingQueue fed by an async callback. When the reading thread is interrupted while blocked in queue.take(), the stream restores the interrupt flag and wraps the InterruptedException in an IOException with this message, since InputStream cannot throw InterruptedException directly.","triggerScenarios":"Calling read() on a QueueInputStream while another thread interrupts the reading thread — typically during executor shutdownNow(), task cancellation, or a timeout mechanism that interrupts worker threads.","commonSituations":"Cancelling a streaming read via Future.cancel(true); shutting down a thread pool with shutdownNow() while a read is pending; application shutdown paths interrupting I/O threads; timeout watchdogs interrupting stalled reads.","solutions":["Handle the IOException and check Thread.currentThread().isInterrupted() to confirm interruption, then abort the read operation gracefully.","If interruption was accidental, remove the interrupt source or ensure no other task shares the reading thread.","Structure shutdown so reads finish (close the stream / deliver EOF_SENTINEL via close()) before interrupting the thread.","Propagate the interrupt state (already preserved by the stream) and retry only if your cancellation policy expects it."],"exampleFix":"// before\nint b = queueStream.read(); // IOException on interrupt\n\n// after\ntry {\n    int b = queueStream.read();\n} catch (IOException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        throw new CancellationException(\"read interrupted\");\n    }\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    int b = queueStream.read();\n} catch (IOException e) {\n    if (Thread.currentThread().isInterrupted()) {\n        // interruption during queue.take(): treat as cancellation\n        cleanup();\n        return; // or rethrow as InterruptedException/CancellationException\n    }\n    throw e;\n}","preventionTips":["Close the stream (which delivers EOF) before interrupting reader threads during shutdown","Avoid shutdownNow() on pools whose tasks are blocked in QueueInputStream.read; drain first","Keep one dedicated thread per stream so unrelated interrupts don't hit reads","Always check isInterrupted() when catching IOException from this stream to distinguish interruption from I/O failure"],"tags":["java","io","concurrency","interruption"],"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"}