apache/cassandra · error · IllegalArgumentException

Reader index should be non-negative, but was

Error message

Reader index should be non-negative, but was ${readerIndex}

What it means

VIntCoding.getUnsignedVInt(ByteBuffer,...) requires readerIndex >= 0 to be able to read the first varint byte; a negative index is a caller bug, so it throws IllegalArgumentException with the offending index. Negative indexes cannot address a ByteBuffer.

Solutions

  1. Validate readerIndex >= 0 before calling, or take readerIndex directly from input.position().
  2. Fix the offset computation that produced the negative value.
  3. Use the accessor-free path with ByteBuffer.position() instead of hand-managed indexes when unsure.

Example fix

// before
long value = VIntCoding.getUnsignedVInt(input, index, input.limit());
// after
int idx = Math.max(0, index);
long value = VIntCoding.getUnsignedVInt(input, idx, input.limit());
Defensive patterns

Strategy: validation

Validate before calling

if (readerIndex < 0 || readerIndex > input.limit()) throw new IllegalArgumentException("bad readerIndex " + readerIndex);

Try / catch

try { long v = VIntCoding.getUnsignedVInt(buf, idx, buf.limit()); } catch (IllegalArgumentException e) { throw new CorruptFrameException(e); }

Prevention

When it happens

Trigger: Passing readerIndex < 0 to getUnsignedVInt(ByteBuffer, int, int), typically from a buffer position that was computed by subtraction, or a decoding loop decrementing past 0.

Common situations: Custom protocol framing code computing offsets from lengths; reusing a readerIndex variable from a previous frame; off-by-one subtraction in parsers.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/fd1087dee227feee. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/utils/vint/VIntCoding.java:239

    public static int getVInt32(ByteBuffer input, int readerIndex)
    {
        return checkedCast(decodeZigZag64(getUnsignedVInt(input, readerIndex)));
    }

    public static long getVInt(ByteBuffer input, int readerIndex)
    {
        return decodeZigZag64(getUnsignedVInt(input, readerIndex));
    }

    public static long getUnsignedVInt(ByteBuffer input, int readerIndex)
    {
        return getUnsignedVInt(input, readerIndex, input.limit());
    }

    public static long getUnsignedVInt(ByteBuffer input, int readerIndex, int readerLimit)
    {
        if (readerIndex < 0)
            throw new IllegalArgumentException("Reader index should be non-negative, but was " + readerIndex);

        if (readerIndex >= readerLimit)
            return -1;

        int firstByte = input.get(readerIndex++);

        //Bail out early if this is one byte, necessary or it fails later
        if (firstByte >= 0)
            return firstByte;

        int size = numberOfExtraBytesToRead(firstByte);
        if (readerIndex + size > readerLimit)
            return -1;

        long retval = firstByte & firstByteValueMask(size);
        for (int ii = 0; ii < size; ii++)
        {
            byte b = input.get(readerIndex++);

View on GitHub (pinned to 88fd0f6a0e)