apache/cassandra · critical · CorruptIndexException

The postings position is less than zero.

Error message

The postings position is less than zero.

What it means

Thrown as a CorruptIndexException when the SAI segment metadata records a negative root position for the POSTING_LISTS component of a numeric index segment. Segment component positions are file offsets into the component files and must never be negative, so a negative value means the metadata was written corruptly or the segment file/metadata pairing is inconsistent. It deliberately names BALANCED_TREE in the component field even when the postings position is the offender, an upstream quirk.

Source

Thrown at src/java/org/apache/cassandra/index/sai/disk/v1/segment/NumericIndexSegmentSearcher.java:66

{
    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    private final BlockBalancedTreeReader treeReader;
    private final QueryEventListener.BalancedTreeEventListener perColumnEventListener;

    NumericIndexSegmentSearcher(PrimaryKeyMap.Factory primaryKeyMapFactory,
                                PerColumnIndexFiles perIndexFiles,
                                SegmentMetadata segmentMetadata,
                                StorageAttachedIndex index) throws IOException
    {
        super(primaryKeyMapFactory, perIndexFiles, segmentMetadata, index);

        final long treePosition = metadata.getIndexRoot(IndexComponent.BALANCED_TREE);
        if (treePosition < 0)
            throw new CorruptIndexException(index.identifier().logMessage("The tree position is less than zero."), IndexComponent.BALANCED_TREE.name);
        final long postingsPosition = metadata.getIndexRoot(IndexComponent.POSTING_LISTS);
        if (postingsPosition < 0)
            throw new CorruptIndexException(index.identifier().logMessage("The postings position is less than zero."), IndexComponent.BALANCED_TREE.name);

        treeReader = new BlockBalancedTreeReader(index.identifier(),
                                                 indexFiles.balancedTree(),
                                                 treePosition,
                                                 indexFiles.postingLists(),
                                                 postingsPosition);
        perColumnEventListener = (QueryEventListener.BalancedTreeEventListener)index.columnQueryMetrics();
    }

    @Override
    public long indexFileCacheSize()
    {
        return treeReader.memoryUsage();
    }

    @Override
    public KeyRangeIterator search(Expression exp, AbstractBounds<PartitionPosition> keyRange, QueryContext context) throws IOException
    {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Run nodetool scrubs/rebuild of the affected SSTables (or REBUILD the secondary index) so the segment is rewritten with valid metadata
  2. Validate the segment file and metadata pairing (matching generation numbers) and restore from a good backup if files were moved manually
  3. Check the storage medium/filesystem for corruption (dmesg, fsck)
  4. If reproducible, file a bug with the segment metadata contents; the check should report the component it validated

Example fix

// before
if (postingsPosition < 0)
    throw new CorruptIndexException(index.identifier().logMessage("The postings position is less than zero."), IndexComponent.BALANCED_TREE.name);
// after
if (postingsPosition < 0)
    throw new CorruptIndexException(index.identifier().logMessage("The postings position is less than zero."), IndexComponent.POSTING_LISTS.name);
Defensive patterns

Strategy: validation

Validate before calling

SegmentMetadata meta = readSegmentMetadata(...);
if (meta.getIndexRoot(IndexComponent.POSTING_LISTS) < 0 || meta.getIndexRoot(IndexComponent.BALANCED_TREE) < 0)
    throw new CorruptIndexException("negative component root in " + index.identifier(), "segment");

Type guard

boolean hasValidRoots(SegmentMetadata m) {
    return m.getIndexRoot(IndexComponent.BALANCED_TREE) >= 0 && m.getIndexRoot(IndexComponent.POSTING_LISTS) >= 0;
}

Prevention

When it happens

Trigger: Opening a numeric SAI segment whose SegmentMetadata contains IndexComponent.POSTING_LISTS root < 0, e.g. after a corrupted flush, truncated SSTable components, or manually edited/copied index files.

Common situations: Disk corruption or incomplete flush during crash, restoring index files from a backup taken mid-flush, mixing segment files from different generations, or running a Cassandra version against index files written by an incompatible one.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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