netty/netty · error · IndexOutOfBoundsException
%s: %d, length: %d (expected: range(0, %d))
Error message
%s: %d, length: %d (expected: range(0, %d))
What it means
Thrown by AbstractByteBuf.rangeBoundsCheckFailed via checkRangeBounds/isOutOfBounds (an IndexOutOfBoundsException). This is the generic workhorse for primitive and indexed get/set operations (e.g. checkIndex0, checkSrcType). isOutOfBounds is true when index < 0, fieldLength < 0, index + fieldLength < 0 (overflow), or index + fieldLength > capacity. indexName is usually 'index', so the message reads e.g. 'index: 5, length: 10 (expected: range(0, 100))'.
Source
Thrown at buffer/src/main/java/io/netty/buffer/AbstractByteBuf.java:1417
}
/**
* This is a simplified version of MathUtil.isOutOfBounds that does not check for capacity negative values.
*/
private static boolean isOutOfBoundsTrustedCapacity(int index, int fieldLength, int capacity) {
// keep these as branches since would make it easier to be constant-folded
return index < 0 || fieldLength < 0 || index + fieldLength < 0 || index + fieldLength > capacity;
}
private static void checkRangeBounds(final String indexName, final int index,
final int fieldLength, final int capacity) {
if (isOutOfBounds(index, fieldLength, capacity)) {
rangeBoundsCheckFailed(indexName, index, fieldLength, capacity);
}
}
private static void rangeBoundsCheckFailed(String indexName, int index, int fieldLength, int capacity) {
throw new IndexOutOfBoundsException(String.format(
"%s: %d, length: %d (expected: range(0, %d))", indexName, index, fieldLength, capacity));
}
final void checkIndex0(int index, int fieldLength) {
if (checkBounds) {
checkRangeBoundsTrustedCapacity("index", index, fieldLength, capacity());
}
}
protected final void checkSrcIndex(int index, int length, int srcIndex, int srcCapacity) {
checkIndex(index, length);
if (checkBounds) {
checkRangeBounds("srcIndex", srcIndex, length, srcCapacity);
}
}
protected final void checkDstIndex(int index, int length, int dstIndex, int dstCapacity) {
checkIndex(index, length);View on GitHub (pinned to 70040aacae)
Solutions
- Validate against the correct bound: use readableBytes() for read-side offsets (index is relative to readerIndex) and capacity() for absolute set operations.
- Sanitize parsed lengths: if (len < 0 || (long) idx + len > buf.capacity()) throw your own clearer error.
- For derived offsets, prefer the read-flavored API (readInt/readBytes) which advances the cursor and bounds-checks against readable bytes automatically.
Example fix
// before
buf.setInt(offset + 4, value); // offset + 4 + 4 > buf.capacity()
// after
int idx = offset + 4;
if (idx < 0 || (long) idx + 4 > buf.capacity()) {
throw new DecoderException("header offset out of range: " + idx);
}
buf.setInt(idx, value); Defensive patterns
Strategy: validation
Validate before calling
// Validate absolute range before indexed get/set
static void ensureRange(ByteBuf buf, int index, int len) {
if (index < 0 || len < 0 || (long) index + len > buf.capacity()) {
throw new IllegalArgumentException("bad range");
}
}
ensureRange(buf, idx, 4);
buf.setInt(idx, value); Type guard
static boolean inRange(ByteBuf buf, int index, int len) {
return index >= 0 && len >= 0 && (long) index + len <= buf.capacity();
} Try / catch
try {
return buf.getInt(idx);
} catch (IndexOutOfBoundsException e) {
throw new DecoderException("field offset " + idx + " out of range", e);
} Prevention
- Use readableBytes() for read-side offsets, capacity() for absolute set operations.
- Sanitize parsed lengths against int overflow before indexing.
- Prefer read-flavored accessors that auto-advance and check readable bytes.
When it happens
Trigger: Calling getInt/setInt/getBytes(index,...)/setBytes(index,...) and similar indexed accessors with a negative index, a negative length, an index+length that overflows int, or an index+length past capacity; reading a field at an offset computed from an attacker-controlled framing length.
Common situations: Decoding variable-length fields where the declared offset/length was not validated against the buffer; off-by-one in offset arithmetic (using capacity vs readableBytes); signed-length bug where a parsed length is negative.
Related errors
- {buffer}.slice({index}, {length})
- readerIndex: %d, writerIndex: %d (expected: 0 <= readerIndex
- writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%
- length(%d) exceeds src.readableBytes(%d) where src is: %s
- length(%d) exceeds dst.writableBytes(%d) where dst is: %s
AI-assisted analysis of netty/netty@70040aacae (2026-08-14).
Data as JSON: /api/errors/952b02501a9f1bf3.
Report an issue: GitHub.