apache/cassandra · error · IndexOutOfBoundsException

Index should be between [0, %d), but was %d.

Error message

Index should be between [0, %d), but was %d.

What it means

AbstractBlockPackedReader.get() validates that the requested valueIndex lies within [0, valueCount) before decoding a block-packed long. An out-of-range index indicates a caller is reading a SAI block-packed file (e.g. a balanced-tree or postings structure) with a position beyond the stored element count, usually meaning metadata/descriptor corruption. The check uses [0, valueCount) despite the '0' in the message string being valueCount — the message formats the bound correctly as the first argument.

Source

Thrown at src/java/org/apache/cassandra/index/sai/disk/v1/bitpack/AbstractBlockPackedReader.java:57

    private long lastIndex; // the last index visited by token -> row ID searches

    AbstractBlockPackedReader(IndexInput indexInput, byte[] blockBitsPerValue, int blockShift, int blockMask, long valueCount)
    {
        this.blockShift = blockShift;
        this.blockMask = blockMask;
        this.valueCount = valueCount;
        this.input = new SeekingRandomAccessInput(indexInput);
        this.blockBitsPerValue = blockBitsPerValue;
    }

    protected abstract long blockOffsetAt(int block);

    @Override
    public long get(final long valueIndex)
    {
        if (valueIndex < 0 || valueIndex >= valueCount)
        {
            throw new IndexOutOfBoundsException(String.format("Index should be between [0, %d), but was %d.", valueCount, valueIndex));
        }

        int blockIndex = (int) (valueIndex >>> blockShift);
        int inBlockIndex = (int) (valueIndex & blockMask);
        byte bitsPerValue = blockBitsPerValue[blockIndex];
        final LongValues subReader = bitsPerValue == 0 ? LongValues.ZEROES
                                                       : DirectReader.getInstance(input, bitsPerValue, blockOffsetAt(blockIndex));
        return delta(blockIndex, inBlockIndex) + subReader.get(inBlockIndex);
    }

    @Override
    public long length()
    {
        return valueCount;
    }

    @Override
    public long indexOf(long value)

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Run nodetool rebuil_index / drop and recreate the SAI index to regenerate the corrupted index files.
  2. Verify index component metadata (valueCount) matches the segment file being read.
  3. Fix the caller to clamp/validate the index against the reader's valueCount before calling get().

Example fix

// before
long v = reader.get(pointId);
// after
if (pointId < 0 || pointId >= reader.valueCount) pointId = Math.min(Math.max(pointId, 0), reader.valueCount - 1);
long v = reader.get(pointId);
Defensive patterns

Strategy: try-catch

Validate before calling

if (valueIndex < 0 || valueIndex >= valueCount) return fallbackValue; // skip get()

Type guard

boolean inRange(long i, long count) { return i >= 0 && i < count; }

Try / catch

try { return reader.get(idx); } catch (IndexOutOfBoundsException e) { log.warn("Corrupt index read", e); return null; }

Prevention

When it happens

Trigger: Calling get(valueIndex) with valueIndex < 0 or valueIndex >= valueCount; internally invoked by midVal and binarySearchBlock during tree searches when a stored tree position or block offset is corrupt.

Common situations: Corrupted or truncated SAI index files on disk, an index descriptor mismatch after a failed compaction/upgrade, or hand-crafted readers seeking with point ids not clamped to the metadata key count.

Related errors


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