apache/cassandra · error · IndexOutOfBoundsException

The target point id [%d] cannot be less than 0 or greater th

Error message

The target point id [%d] cannot be less than 0 or greater than or equal to the key count [%d]

What it means

KeyLookup.seekToPointId() requires the target point id to be within [0, keyCount) before positioning its block-packed reader over the key store. Point ids are dense row ids; seeking outside that range would decode bogus key data, so it fails fast with IndexOutOfBoundsException. The javadoc notes -1 is tolerated by the adjacent seekBefore variant, but this method rejects anything below 0.

Source

Thrown at src/java/org/apache/cassandra/index/sai/disk/v1/keystore/KeyLookup.java:154

            this.nextBlockKey = new BytesRef(keyLookupMeta.maxKeyLength);
            keysInput.seek(keysFilePointer);
            readKey(currentPointId, currentKey);
        }

        /**
         * Positions the cursor on the target point id and reads the key at the target to the current key buffer.
         * <p>
         * It is allowed to position the cursor before the first item or after the last item;
         * in these cases the internal buffer is cleared.
         *
         * @param pointId point id to lookup
         * @return The {@link ByteSource} containing the key
         * @throws IndexOutOfBoundsException if the target point id is less than -1 or greater than the number of keys
         */
        public @Nonnull ByteSource seekToPointId(long pointId)
        {
            if (pointId < 0 || pointId >= keyLookupMeta.keyCount)
                throw new IndexOutOfBoundsException(String.format(INDEX_OUT_OF_BOUNDS, pointId, keyLookupMeta.keyCount));

            if (pointId != currentPointId)
            {
                long blockIndex = pointId >>> blockShift;
                // We need to reset the block if the block index has changed or the pointId < currentPointId.
                // We can read forward in the same block without a reset, but we can't read backwards, and token
                // collision can result in us moving backwards.
                if (blockIndex != currentBlockIndex || pointId < currentPointId)
                {
                    currentBlockIndex = blockIndex;
                    resetToCurrentBlock();
                }
            }
            while (currentPointId < pointId)
            {
                currentPointId++;
                readCurrentKey();
                updateCurrentBlockIndex(currentPointId);

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Rebuild the affected SAI index (nodetool rebuild_index or DROP/CREATE INDEX) to regenerate consistent components.
  2. Validate that postings rowids never exceed segmentMetadata keyCount in the writer path.
  3. Check disk health / file corruption and restore from a clean snapshot if components are truncated.

Example fix

// before
ByteSource key = keyLookup.seekToPointId(rowId);
// after
if (rowId >= 0 && rowId < keyLookupMeta.keyCount)
    ByteSource key = keyLookup.seekToPointId(rowId);
Defensive patterns

Strategy: validation

Validate before calling

if (pointId < 0 || pointId >= keyLookupMeta.keyCount) return null;

Type guard

boolean validPointId(long id, long keyCount) { return id >= 0 && id < keyCount; }

Try / catch

try { return keyLookup.seekToPointId(id); } catch (IndexOutOfBoundsException e) { log.warn("rowid {} out of range — corrupt segment", id, e); return null; }

Prevention

When it happens

Trigger: A balanced-tree or postings iterator resolves a rowid/point id that is >= the segment metadata keyCount or negative, then calls keyLookup.seekToPointId(pointId) during a primary-key map lookup.

Common situations: Corrupted or mismatched SAI segment components (postings referencing rowids that no longer exist), partially-written segments after a crash, or version-skew between index descriptor and data files.

Related errors


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