{"record":{"id":"fd1087dee227feee","repo":"apache/cassandra","slug":"reader-index-should-be-non-negative-but-was-rea","errorCode":null,"errorMessage":"Reader index should be non-negative, but was ${readerIndex}","messagePattern":"Reader index should be non-negative, but was (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/utils/vint/VIntCoding.java","lineNumber":239,"sourceCode":"    public static int getVInt32(ByteBuffer input, int readerIndex)\n    {\n        return checkedCast(decodeZigZag64(getUnsignedVInt(input, readerIndex)));\n    }\n\n    public static long getVInt(ByteBuffer input, int readerIndex)\n    {\n        return decodeZigZag64(getUnsignedVInt(input, readerIndex));\n    }\n\n    public static long getUnsignedVInt(ByteBuffer input, int readerIndex)\n    {\n        return getUnsignedVInt(input, readerIndex, input.limit());\n    }\n\n    public static long getUnsignedVInt(ByteBuffer input, int readerIndex, int readerLimit)\n    {\n        if (readerIndex < 0)\n            throw new IllegalArgumentException(\"Reader index should be non-negative, but was \" + readerIndex);\n\n        if (readerIndex >= readerLimit)\n            return -1;\n\n        int firstByte = input.get(readerIndex++);\n\n        //Bail out early if this is one byte, necessary or it fails later\n        if (firstByte >= 0)\n            return firstByte;\n\n        int size = numberOfExtraBytesToRead(firstByte);\n        if (readerIndex + size > readerLimit)\n            return -1;\n\n        long retval = firstByte & firstByteValueMask(size);\n        for (int ii = 0; ii < size; ii++)\n        {\n            byte b = input.get(readerIndex++);","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/utils/vint/VIntCoding.java#L221-L257","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom protocol framing code computing offsets from lengths; reusing a readerIndex variable from a previous frame; off-by-one subtraction in parsers.","solutions":["Validate readerIndex >= 0 before calling, or take readerIndex directly from input.position().","Fix the offset computation that produced the negative value.","Use the accessor-free path with ByteBuffer.position() instead of hand-managed indexes when unsure."],"exampleFix":"// before\nlong value = VIntCoding.getUnsignedVInt(input, index, input.limit());\n// after\nint idx = Math.max(0, index);\nlong value = VIntCoding.getUnsignedVInt(input, idx, input.limit());","handlingStrategy":"validation","validationCode":"if (readerIndex < 0 || readerIndex > input.limit()) throw new IllegalArgumentException(\"bad readerIndex \" + readerIndex);","typeGuard":null,"tryCatchPattern":"try { long v = VIntCoding.getUnsignedVInt(buf, idx, buf.limit()); } catch (IllegalArgumentException e) { throw new CorruptFrameException(e); }","preventionTips":["Derive readerIndex from input.position() instead of manual subtraction.","Track decode offsets with non-decreasing counters and bounds checks each step."],"tags":["vint","serialization","validation","java"],"backgroundTag":"argument-out-of-range","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}