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
- Rebuild the affected SAI index (nodetool rebuild_index or DROP/CREATE INDEX) to regenerate consistent components.
- Validate that postings rowids never exceed segmentMetadata keyCount in the writer path.
- 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
- Clamp postings rowids to segmentMetadata keyCount before lookups.
- Rebuild SAI indexes after unclean shutdowns if corruption is suspected.
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
- Index should be between [0, %d), but was %d.
- Invalid block offset %d for postings block idx %d
- Postings list #%s block is corrupted. Bits per value should
- The tree position is less than zero.
- The postings position is less than zero.
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/6fcf74ae2f0a8cb4.
Report an issue: GitHub.