github/copilot-sdk · error · IndexOutOfBoundsException
Invalid off/len for buffer of length + b.length
Error message
Invalid off/len for buffer of length + b.length
What it means
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.
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.
Example fix
// before int n = queueStream.read(buf, off, buf.length); // off+len > buf.length // after int n = queueStream.read(buf, off, Math.min(buf.length - off, wanted));
Defensive patterns
Strategy: validation
Validate before calling
if (off < 0 || len < 0 || off + len > buf.length) {
throw new IllegalArgumentException("bad off/len: off=" + off + " len=" + len + " buf=" + buf.length);
}
queueStream.read(buf, off, len); Type guard
static boolean isValidSlice(byte[] b, int off, int len) {
return b != null && off >= 0 && len >= 0 && off <= b.length && len <= b.length - off;
} Try / catch
try {
n = queueStream.read(buf, off, len);
} catch (IndexOutOfBoundsException e) {
// fix arguments, do not retry blindly
len = Math.max(0, Math.min(len, buf.length - off));
n = queueStream.read(buf, off, len);
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Invalid off/len for buffer of length
- Interrupted while waiting for callback data
- Unknown WorkspaceDiffFileChangeType value
- Unknown WorkspaceDiffMode value
- Unknown WorkspaceSummaryHostType value
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/c98d850ee9942f7b.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/ffi/QueueInputStream.java:70
}
queue.offer(bytes);
}
@Override
public int read() throws IOException {
byte[] one = new byte[1];
int read = read(one, 0, 1);
if (read == -1) {
return -1;
}
return one[0] & 0xFF;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
Objects.requireNonNull(b, "buffer must not be null");
if (off < 0 || len < 0 || off + len > b.length) {
throw new IndexOutOfBoundsException("Invalid off/len for buffer of length " + b.length);
}
if (len == 0) {
return 0;
}
if (eof) {
return -1;
}
while (currentChunk == null || currentOffset >= currentChunk.length) {
byte[] next;
try {
next = queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted while waiting for callback data", e);
}
if (next == EOF_SENTINEL) {
eof = true;View on GitHub (pinned to cd8cf15dc3)