{"record":{"id":"c98d850ee9942f7b","repo":"github/copilot-sdk","slug":"invalid-off-len-for-buffer-of-length-b-length","errorCode":null,"errorMessage":"Invalid off/len for buffer of length + b.length","messagePattern":"Invalid off/len for buffer of length \\+ b\\.length","errorType":"validation","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/ffi/QueueInputStream.java","lineNumber":70,"sourceCode":"        }\n        queue.offer(bytes);\n    }\n\n    @Override\n    public int read() throws IOException {\n        byte[] one = new byte[1];\n        int read = read(one, 0, 1);\n        if (read == -1) {\n            return -1;\n        }\n        return one[0] & 0xFF;\n    }\n\n    @Override\n    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;","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/ffi/QueueInputStream.java#L52-L88","documentation":"QueueInputStream.read(byte[], int, int) validates the offset/length arguments against the caller's buffer before reading any queued data. If off or len is negative, or off+len exceeds b.length, it throws IndexOutOfBoundsException naming the buffer's length. This mirrors the contract of java.io.InputStream and fails fast instead of throwing a confusing ArrayIndexOutOfBoundsException later.","triggerScenarios":"Calling read(buf, off, len) on a QueueInputStream with a negative off, a negative len, or off+len > buf.length, e.g. read(buf, buf.length, 1) or read(buf, 5, buf.length).","commonSituations":"Hand-computed offsets from a loop that forgets to clamp the last chunk; a wrapper stream passing through caller-controlled off/len without validation; off-by-one errors after resuming a partial read; passing a different (smaller) buffer than the one whose length was used to compute off.","solutions":["Check arguments before the call: ensure off >= 0, len >= 0, and off + len <= buffer.length.","Clamp len to the remaining space: len = Math.min(len, buffer.length - off).","If computing off/len from a cursor, recompute both from the same buffer instance."],"exampleFix":"// before\nint n = queueStream.read(buf, off, buf.length); // off+len > buf.length\n\n// after\nint n = queueStream.read(buf, off, Math.min(buf.length - off, wanted));","handlingStrategy":"validation","validationCode":"if (off < 0 || len < 0 || off + len > buf.length) {\n    throw new IllegalArgumentException(\"bad off/len: off=\" + off + \" len=\" + len + \" buf=\" + buf.length);\n}\nqueueStream.read(buf, off, len);","typeGuard":"static boolean isValidSlice(byte[] b, int off, int len) {\n    return b != null && off >= 0 && len >= 0 && off <= b.length && len <= b.length - off;\n}","tryCatchPattern":"try {\n    n = queueStream.read(buf, off, len);\n} catch (IndexOutOfBoundsException e) {\n    // fix arguments, do not retry blindly\n    len = Math.max(0, Math.min(len, buf.length - off));\n    n = queueStream.read(buf, off, len);\n}","preventionTips":["Prefer single-arg read() or readAllBytes over manual off/len when possible","Clamp len with Math.min(len, buf.length - off)","Derive off and len from the same buffer instance","Unit-test partial-read loops for the final chunk boundary"],"tags":["java","io","stream","bounds"],"backgroundTag":"index-out-of-range","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"}