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

  1. Check arguments before the call: ensure off >= 0, len >= 0, and off + len <= buffer.length.
  2. Clamp len to the remaining space: len = Math.min(len, buffer.length - off).
  3. 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

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


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)