apache/pulsar · error · IndexOutOfBoundsException

off=${off}, len=${len}, b.length=${b.length}

Error message

off=${off}, len=${len}, b.length=${b.length}

What it means

BlockAwareSegmentInputStreamImpl.read(byte[], int, int) enforces InputStream argument bounds: if off < 0, len < 0, or len > b.length - off, it throws IndexOutOfBoundsException with the offending off/len/b.length values.

Source

Thrown at tiered-storage/jcloud/src/main/java/org/apache/bookkeeper/mledger/offload/jcloud/impl/BlockAwareSegmentInputStreamImpl.java:223

                entries.add(entryBuf);
            }
            return entries;
        } catch (InterruptedException | ExecutionException e) {
            log.error().exception(e).log("Exception when getting LedgerEntries");
            if (e instanceof InterruptedException) {
                Thread.currentThread().interrupt();
            }
            throw new IOException(e);
        }
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException("The given bytes are null");
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + ", b.length=" + b.length);
        } else if (len == 0) {
            return 0;
        }

        int offset = off;
        int readLen = len;
        int readBytes = 0;
        // reading header
        if (dataBlockHeaderStream.available() > 0) {
            int read = dataBlockHeaderStream.read(b, off, len);
            offset += read;
            readLen -= read;
            readBytes += read;
            bytesReadOffset += read;
        }
        if (readLen == 0) {
            return readBytes;
        }

View on GitHub (pinned to 820761864e)

Solutions

  1. Validate before calling: ensure 0 <= off <= b.length and 0 <= len <= b.length - off
  2. Clamp len to Math.min(len, b.length - off) and bail out when it becomes <= 0
  3. Check block-size/off calculations in the offload copy loop

Example fix

// before
int n = stream.read(buf, off, buf.length); // IOOBE when off > 0
// after
int len = Math.min(requested, buf.length - off);
int n = len > 0 ? stream.read(buf, off, len) : -1;
Defensive patterns

Strategy: validation

Validate before calling

static int[] validated(byte[] b, int off, int len) {
  if (off < 0 || len < 0 || len > b.length - off)
    throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + ", b.length=" + b.length);
  return new int[]{off, len};
}

Type guard

static boolean inBounds(byte[] b, int off, int len) {
  return b != null && off >= 0 && len >= 0 && len <= b.length - off;
}

Try / catch

try {
  int n = stream.read(buf, off, len);
} catch (IndexOutOfBoundsException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("off=")) {
    off = 0; len = Math.min(len, buf.length); // recompute and retry
  } else throw e;
}

Prevention

When it happens

Trigger: Calling read(b, off, len) where off+len exceeds the buffer length, or off/len is negative — e.g. computing len from remaining bytes without clamping after EOF.

Common situations: Caller computing len = buffer.length - off with an off larger than the buffer; retry loops not shrinking len after partial reads; mismatched block-size constants between writer and reader.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/3c71ec61e00881c9. Report an issue: GitHub.