apache/cassandra · critical · java.io.IOException
Corrupt flags value for clustering prefix (isStatic flag set
Error message
Corrupt flags value for clustering prefix (isStatic flag set): <flags>
What it means
When deserializing an unfiltered (row/static-row) from an sstable or commit log, the extended flags indicate whether the next unfiltered is a static row or a regular row with a clustering prefix. If the isStatic bit is set in extendedFlags but the code is reading a clustering prefix, the on-disk data is structurally corrupt. This IOException guards the deserializer against misinterpreting the byte stream.
Source
Thrown at src/java/org/apache/cassandra/db/ClusteringPrefix.java:664
private long nextHeader;
private int nextSize;
private ClusteringPrefix.Kind nextKind;
private int deserializedSize;
private byte[][] nextValues;
private final ValueAccessor<byte[]> accessor = ByteArrayAccessor.instance;
public Deserializer(ClusteringComparator comparator, DataInputPlus in, SerializationHeader header)
{
this.comparator = comparator;
this.in = in;
this.serializationHeader = header;
}
public void prepare(int flags, int extendedFlags) throws IOException
{
if (UnfilteredSerializer.isStatic(extendedFlags))
throw new IOException("Corrupt flags value for clustering prefix (isStatic flag set): " + flags);
this.nextIsRow = UnfilteredSerializer.kind(flags) == Unfiltered.Kind.ROW;
this.nextKind = nextIsRow ? Kind.CLUSTERING : Kind.fromOrdinal(in.readByte());
this.nextSize = nextIsRow ? comparator.size() : in.readUnsignedShort();
this.deserializedSize = 0;
// The point of the deserializer is that some of the clustering prefix won't actually be used (because they are not
// within the bounds of the query), and we want to reduce allocation for them. So we only reuse the values array
// between elements if 1) we haven't returned the previous element (if we have, nextValues will be null) and 2)
// nextValues is of the proper size. Note that the 2nd condition may not hold for range tombstone bounds, but all
// rows have a fixed size clustering, so we'll still save in the common case.
if (nextValues == null || nextValues.length != nextSize)
this.nextValues = new byte[nextSize][];
}
public <T> int compareNextTo(ClusteringBoundOrBoundary<T> bound) throws IOException
{
if (bound.isTop())View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Run nodetool scrub on the affected table to repair or drop corrupt sstables
- Restore the affected sstables/commit logs from a known-good backup
- Check disk health (SMART, filesystem check) and replace failing hardware
- File an issue with the exact sstable/version if corruption appears reproducible on clean data
Example fix
// before // node fails reading corrupt sstable during compaction/read // after nodetool scrub --skip-corrupted <keyspace> <table> // then repair re-replicates from other replicas
Defensive patterns
Strategy: retry
Try / catch
try { iterateSstables(...); } catch (IOException e) { if (e.getMessage().contains("Corrupt flags value")) { scheduleScrub(keyspace, table); alertCorruption(e); } else throw e; } Prevention
- Run nodetool scrub periodically and after unclean shutdowns
- Monitor disk health and use checksumming filesystems/RAID
- Never hand-edit or partially copy sstable/commit-log files; move them with their _txn companions
When it happens
Trigger: UnfilteredSerializer deserialization path calling Deserializer.prepare(flags, extendedFlags) with UnfilteredSerializer.isStatic(extendedFlags) == true while reading what should be a clustering prefix.
Common situations: Bitrot/corruption on disk, truncated or hand-edited sstable/commit-log files, bugs in other writers, or restoring files from mismatched backups.
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
- Invalid Columns subset bytes; too many bits set: ${encoded}
- Invalid large Columns subset: missing count ${encoded} of ${
- Invalid large Columns subset: present index ${idx} of ${supe
- Invalid large Columns subset: missing index ${idx} of ${supe
- Unknown column <name> during deserialization
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/e4f6b6a144b892bb.
Report an issue: GitHub.