apache/cassandra · critical · CorruptSSTableException

CorruptSSTableException wrapping deserialization failure for

Error message

CorruptSSTableException wrapping deserialization failure for ${filename}

What it means

When SSTableCursorReader hits a deserialization/IO failure, corruptSSTable(Exception) marks the sstable reader suspect (blacklisting it for reads), rethrows CorruptSSTableException as-is, or wraps any other exception in a new CorruptSSTableException carrying the sstable filename. This is the corruption funnel so callers always see a uniform corrupt-sstable signal.

Source

Thrown at src/java/org/apache/cassandra/io/sstable/SSTableCursorReader.java:1441

        // raw AssertionError.
        if (dataReader.getPosition() != unfilteredEnd)
            corruptSSTable("cell desync: cells consumed to " + dataReader.getPosition()
                            + ", unfiltered body declared end " + unfilteredEnd);
        unfilteredEnd = NO_UNFILTERED_END;

        long preFlagsPosition = dataReader.getPosition();
        int flags = this.basicUnfilteredFlags = dataReader.readUnsignedByte();
        readRowExtendedFlags(flags, false, preFlagsPosition);
        return this.state = CELL_END;
    }

    private int corruptSSTable(Exception e)
    {
        ssTableReader.markSuspect();
        if (e instanceof CorruptSSTableException)
            throw (CorruptSSTableException) e;

        throw new CorruptSSTableException(e, ssTableReader.getFilename());
    }

    protected int corruptSSTable(String message)
    {
        return corruptSSTable(new IllegalStateException(message));
    }

    private int nextStateMidPartition(int basicUnfilteredFlags)
    {
        if (UnfilteredSerializer.isEndOfPartition(basicUnfilteredFlags))
        {
            return afterPartitionEnd();
        }
        else if (UnfilteredSerializer.isRow(basicUnfilteredFlags))
        {
            return ROW_START;
        }
        else

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Inspect getCause() to find the root failure and affected file.
  2. Run nodetool verify on the named sstable to confirm corruption.
  3. Run nodetool scrub / sstablescrub on the keyspace/table; the file is already marked suspect so reads avoid it.
  4. Restore from backup and run nodetool repair to restore full replicas.
  5. If the cause is schema mismatch rather than bad bytes, fix schema agreement instead of scrubbing.

Example fix

// before
catch (Exception e) {
    throw new RuntimeException("read failed", e); // loses corruption semantics
}
// after
catch (Exception e) {
    ssTableReader.markSuspect();
    throw (e instanceof CorruptSSTableException)
        ? (CorruptSSTableException) e
        : new CorruptSSTableException(e, ssTableReader.getFilename());
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    while (cursor.hasNext()) { cursor.next(); }
} catch (CorruptSSTableException e) {
    logger.warn("SSTable corrupt: {}", e.getFilename());
    // schedule scrub/repair; reads avoid the suspect sstable automatically
}

Prevention

When it happens

Trigger: Any IOException, negative clustering length, bad end-of-partition marker, or bad clustering header raised during cursor iteration is caught and passed to corruptSSTable(e); corruptSSTable(String) wraps IllegalStateExceptions with a message.

Common situations: Reading on-disk-corrupt sstables; schema mismatches during reads; truncated data files; compaction or read-path failures surfaced as CorruptSSTableException.

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