apache/cassandra · critical · IOException
Corrupted sstable. Invalid flags found deserializing Deletio
Error message
Corrupted sstable. Invalid flags found deserializing DeletionTime: " + Integer.toBinaryString(flags & 0xFF)
What it means
DeletionTime.Serializer.deserialize(DataInputPlus) reads a one-byte flags field from the wire. The top bit (IS_LIVE_DELETION) marks a live (non-deleted) DeletionTime; if it is set but any of the other 7 bits are also set, the encoding is not a valid live marker, so the deserializer throws an IOException declaring the sstable corrupted. This guards against reading data written by incompatible versions or truncated/corrupted files.
Source
Thrown at src/java/org/apache/cassandra/db/DeletionTime.java:256
public void serialize(DeletionTime delTime, DataOutputPlus out) throws IOException
{
if (delTime == LIVE || delTime.isLive())
out.writeByte(IS_LIVE_DELETION);
else
{
// The sign bit is zero here, so we can write a long directly
out.writeLong(delTime.markedForDeleteAt());
out.writeInt(delTime.localDeletionTimeUnsignedInteger);
}
}
public DeletionTime deserialize(DataInputPlus in) throws IOException
{
int flags = in.readByte();
if ((flags & IS_LIVE_DELETION) != 0)
{
if ((flags & 0xFF) != IS_LIVE_DELETION)
throw new IOException("Corrupted sstable. Invalid flags found deserializing DeletionTime: " + Integer.toBinaryString(flags & 0xFF));
return LIVE;
}
else
{
// Read the remaining 7 bytes
int bytes1 = in.readByte();
int bytes2 = in.readShort();
int bytes4 = in.readInt();
long mfda = readBytesToMFDA(flags, bytes1, bytes2, bytes4);
int localDeletionTimeUnsignedInteger = in.readInt();
return new ImmutableDeletionTime(mfda, localDeletionTimeUnsignedInteger);
}
}
public void deserialize(DataInputPlus in, ReusableDeletionTime reuse) throws IOException
{View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Run `nodetool scrub` (or `sstablescrub`) on the affected table to repair or drop the corrupted sstable.
- Verify disk/RAM health (smartctl, fsck) and restore the affected sstables from a backup or by rebuilding via repair (`nodetool repair`) from replicas.
- Check that all nodes run compatible Cassandra versions and that no partial writes (e.g. from a crash during compaction) remain; delete leftover temp sstables.
- Reproduce with the DeletionTime serializer unit tests to confirm the flags encoding on your build is 0x80 for live deletions.
Example fix
// before: blindly deserializing a possibly-corrupt stream
DeletionTime dt = DeletionTime.serializer.deserialize(in);
// after: validate flags yourself and fail fast with context
int flags = in.readByte();
if ((flags & 0x80) != 0 && (flags & 0xFF) != 0x80)
throw new CorruptSSTableException(new IOException("Bad DeletionTime flags: " + Integer.toBinaryString(flags & 0xFF)), file); Defensive patterns
Strategy: try-catch
Validate before calling
// before deserializing from an untrusted file, validate sstable integrity File sstable = new File(path); if (!Digest.validate(sstable, digestFile)) throw new CorruptSSTableException(...);
Type guard
// check the flags byte yourself before full deserialize
static boolean isValidDeletionTimeFlags(int flags) {
return (flags & 0x80) == 0 || (flags & 0xFF) == 0x80;
}
Try / catch
try {
DeletionTime dt = DeletionTime.serializer.deserialize(in);
} catch (IOException e) {
if (e.getMessage().contains("Invalid flags found deserializing DeletionTime"))
throw new CorruptSSTableException(e, sstableFile); // trigger repair/scrub
throw e;
}
Prevention
- Run `nodetool scrub` periodically and `nodetool repair` after disk incidents.
- Use ECC RAM and monitor disk SMART health.
- Keep all cluster nodes on the same, current Cassandra version.
- Never hand-edit or truncate sstable files.
When it happens
Trigger: Reading a Memtable/SSTable-backed partition or an index entry (IndexedEntry), or test/testE2EDeSerializeDT deserialization paths, where the byte read at the DeletionTime position has bit 0x80 set together with other bits (e.g. flags != 0x80). Caused by byte-stream misalignment, corruption, or a writer producing a malformed encoding.
Common situations: Bit-flip disk corruption or truncation of SSTable files; hand-crafted or corrupted commitlog/memtable data; reading sstables produced by a broken build or different Cassandra version with a changed on-wire format; failed reads surfaced via CorruptSSTableException wrappers in logs.
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
- Corrupt flags value for clustering prefix (isStatic flag set
- Failed to import sstable <filename>
- Seeking to a partition at: ${position} did not land after an
- CorruptSSTableException wrapping IOException for ${path}
- CorruptSSTableException wrapping IOException cause for ${fil
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/d070dcc1c6ce2aff.
Report an issue: GitHub.