{"record":{"id":"e4f6b6a144b892bb","repo":"apache/cassandra","slug":"corrupt-flags-value-for-clustering-prefix-isstati","errorCode":null,"errorMessage":"Corrupt flags value for clustering prefix (isStatic flag set): <flags>","messagePattern":"Corrupt flags value for clustering prefix \\(isStatic flag set\\): <flags>","errorType":"exception","errorClass":"java.io.IOException","httpStatus":null,"severity":"critical","filePath":"src/java/org/apache/cassandra/db/ClusteringPrefix.java","lineNumber":664,"sourceCode":"        private long nextHeader;\n\n        private int nextSize;\n        private ClusteringPrefix.Kind nextKind;\n        private int deserializedSize;\n        private byte[][] nextValues;\n        private final ValueAccessor<byte[]> accessor = ByteArrayAccessor.instance;\n\n        public Deserializer(ClusteringComparator comparator, DataInputPlus in, SerializationHeader header)\n        {\n            this.comparator = comparator;\n            this.in = in;\n            this.serializationHeader = header;\n        }\n\n        public void prepare(int flags, int extendedFlags) throws IOException\n        {\n            if (UnfilteredSerializer.isStatic(extendedFlags))\n                throw new IOException(\"Corrupt flags value for clustering prefix (isStatic flag set): \" + flags);\n\n            this.nextIsRow = UnfilteredSerializer.kind(flags) == Unfiltered.Kind.ROW;\n            this.nextKind = nextIsRow ? Kind.CLUSTERING : Kind.fromOrdinal(in.readByte());\n            this.nextSize = nextIsRow ? comparator.size() : in.readUnsignedShort();\n            this.deserializedSize = 0;\n\n            // The point of the deserializer is that some of the clustering prefix won't actually be used (because they are not\n            // within the bounds of the query), and we want to reduce allocation for them. So we only reuse the values array\n            // between elements if 1) we haven't returned the previous element (if we have, nextValues will be null) and 2)\n            // nextValues is of the proper size. Note that the 2nd condition may not hold for range tombstone bounds, but all\n            // rows have a fixed size clustering, so we'll still save in the common case.\n            if (nextValues == null || nextValues.length != nextSize)\n                this.nextValues = new byte[nextSize][];\n        }\n\n        public <T> int compareNextTo(ClusteringBoundOrBoundary<T> bound) throws IOException\n        {\n            if (bound.isTop())","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/ClusteringPrefix.java#L646-L682","documentation":"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.","triggerScenarios":"UnfilteredSerializer deserialization path calling Deserializer.prepare(flags, extendedFlags) with UnfilteredSerializer.isStatic(extendedFlags) == true while reading what should be a clustering prefix.","commonSituations":"Bitrot/corruption on disk, truncated or hand-edited sstable/commit-log files, bugs in other writers, or restoring files from mismatched backups.","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"],"exampleFix":"// before\n// node fails reading corrupt sstable during compaction/read\n// after\nnodetool scrub --skip-corrupted <keyspace> <table>  // then repair re-replicates from other replicas","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { iterateSstables(...); } catch (IOException e) { if (e.getMessage().contains(\"Corrupt flags value\")) { scheduleScrub(keyspace, table); alertCorruption(e); } else throw e; }","preventionTips":["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"],"tags":["cassandra","corruption","sstable","deserialization","io"],"backgroundTag":"checksum-mismatch","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}