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

  1. Run nodetool scrub on the affected table to repair or drop corrupt sstables
  2. Restore the affected sstables/commit logs from a known-good backup
  3. Check disk health (SMART, filesystem check) and replace failing hardware
  4. 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

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


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