apache/cassandra · warning

Data file partition position

Error message

Data file partition position %d differs from index file row position %d

What it means

During BTI scrub, when both the data file and the index are readable, the scrubber compares the partition's start position in the data file (dataStart) against the position recorded in the index (dataStartFromIndex). If they differ, the index and data are out of sync; the scrubber logs this warning but keeps going, relying on later consistency checks and retry logic to handle the bad partition.

Solutions

  1. Let the scrub continue; it tracks mismatches and can retry/skip affected partitions.
  2. After scrub, compact the table to produce a consistent data+index pair.
  3. Verify the sstable set is intact and matched: do not copy .db component files independently across generation directories.
  4. If mismatches are widespread, restore the sstables from backup and run `nodetool repair`.

Example fix

// Preventive operational fix: keep data+index components together
// before: rsync only *-Data.db between snapshot dirs
// after: copy the whole sstable component set (Data.db, Index.db, etc.) from one snapshot
Defensive patterns

Strategy: validation

Validate before calling

// Ensure data and index belong to the same sstable generation before restore
$ ls data/ks/tbl-<uuid>/  # copy the FULL component set xx-* (Data.db, Index.db, Statistics.db, TOC.txt)
# Never mix components from different generations (different numeric prefixes)

Prevention

When it happens

Trigger: `nodetool scrub` on a BTI sstable where an index entry's recorded data offset no longer matches the actual partition offset in the data file — e.g. the data file was altered, truncated, or the index was written against different content.

Common situations: Sstable data and index files mixed from different compaction generations (files copied/replaced independently); partial writes after crash; manual file manipulation or bad restore.

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/88c6531ec1c3e57b. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/io/sstable/format/bti/BtiTableScrubber.java:185

            String keyName = key == null ? "(unreadable key)" : keyString(key);
            outputHandler.debug("partition %s is %s", keyName, FBUtilities.prettyPrintMemory(dataSizeFromIndex));

            try
            {
                if (key == null)
                    throw new IOError(new IOException("Unable to read partition key from data file", keyReadError));

                if (currentIndexKey != null && !key.getKey().equals(currentIndexKey))
                {
                    throw new IOError(new IOException(String.format("Key from data file (%s) does not match key from index file (%s)",
                                                                    ByteBufferUtil.bytesToHex(key.getKey()), ByteBufferUtil.bytesToHex(currentIndexKey))));
                }

                if (indexIterator != null && dataSizeFromIndex > dataFile.length())
                    throw new IOError(new IOException("Impossible partition size (greater than file length): " + dataSizeFromIndex));

                if (indexIterator != null && dataStart != dataStartFromIndex)
                    outputHandler.warn("Data file partition position %d differs from index file row position %d", dataStart, dataStartFromIndex);

                if (tryAppend(prevKey, key, writer))
                    prevKey = key;
            }
            catch (Throwable th)
            {
                throwIfFatal(th);
                outputHandler.warn(th, "Error reading partition %s (stacktrace follows):", keyName);

                if (currentIndexKey != null
                    && (key == null || !key.getKey().equals(currentIndexKey) || dataStart != dataStartFromIndex))
                {

                    // position where the row should start in a data file (right after the partition key)
                    long rowStartFromIndex = dataStartFromIndex + TypeSizes.SHORT_SIZE + currentIndexKey.remaining();
                    outputHandler.output("Retrying from partition index; data is %s bytes starting at %s",
                                         dataSizeFromIndex, rowStartFromIndex);
                    key = sstable.decorateKey(currentIndexKey);

View on GitHub (pinned to 88fd0f6a0e)