{"record":{"id":"9131e3d3227a05b0","repo":"apache/cassandra","slug":"invalid-large-columns-subset-missing-count-enco","errorCode":null,"errorMessage":"Invalid large Columns subset: missing count ${encoded} of ${supersetCount}","messagePattern":"Invalid large Columns subset: missing count (.+?) of (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/io/sstable/UnfilteredDescriptor.java","lineNumber":190,"sourceCode":"        // Mirrors the corruption check in Columns.Serializer.deserializeSubset.\n        if ((encoded >>> rowColumns.size()) != 0)\n            throw new IOException(\"Invalid Columns subset bytes; too many bits set: \" + Long.toBinaryString(encoded));\n        missingColumnsMask = encoded;\n    }\n\n    /**\n     * Wire format per Columns.Serializer.serializeLargeSubset: an unsigned vint delta of\n     * supersetCount - presentCount, then one unsigned vint superset index per column. The indices\n     * name the present columns when presentCount is under half the superset, and the missing\n     * columns otherwise. Decoding into reusable mask words leaves rowColumns as the superset, so\n     * CellCursor never rebuilds its per-superset arrays.\n     */\n    private void readLargeColumnsSubset(RandomAccessReader dataReader) throws IOException\n    {\n        long encoded = dataReader.readUnsignedVInt();\n        int supersetCount = rowColumns.size();\n        if (encoded > supersetCount)\n            throw new IOException(\"Invalid large Columns subset: missing count \" + encoded + \" of \" + supersetCount);\n\n        int delta = (int) encoded;\n        int columnCount = supersetCount - delta;\n        int nWords = (supersetCount + 63) >>> 6;\n        if (presentColumnsWords == null || presentColumnsWords.length < nWords)\n            presentColumnsWords = new long[nWords];\n\n        if (columnCount < supersetCount / 2)\n            readPresentColumnIndexes(dataReader, supersetCount, nWords, columnCount);\n        else\n            readMissingColumnIndexes(dataReader, supersetCount, nWords, delta);\n\n        useColumnsWords = true;\n        missingColumnsMask = 0;\n    }\n\n    private void readPresentColumnIndexes(RandomAccessReader dataReader, int supersetCount, int nWords, int columnCount) throws IOException\n    {","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/io/sstable/UnfilteredDescriptor.java#L172-L208","documentation":"UnfilteredDescriptor.readLargeColumnsSubset decodes a 'large' Columns subset as an unsigned vint 'missing count' delta (supersetCount - presentCount). If the encoded missing count exceeds the superset column count the value cannot be valid, so the reader throws IOException ('Invalid large Columns subset: missing count N of M') indicating corrupt or misaligned sstable bytes (src/java/org/apache/cassandra/io/sstable/UnfilteredDescriptor.java:190).","triggerScenarios":"Reading an sstable descriptor block where the large-subset unsigned vint decodes to a missing-count greater than rowColumns.size(): corruption at that offset, reading at the wrong file position, truncation followed by re-read of stale bytes, or a format/version mismatch between writer and reader.","commonSituations":"Failing disks producing bit-rot in sstable files; incomplete file copies or restores that shift offsets; nodes upgraded/downgraded across sstable format versions reading files they shouldn't; streaming interrupted sstables being opened.","solutions":["Run nodetool verify/scrub on the keyspace to detect and remove the corrupt sstable","Restore the damaged sstable from snapshot/backup or run repair so other replicas rebuild the lost ranges","Check disk health for the data directory and replace failing hardware","Verify the sstable format matches the running Cassandra version; re-upgrade or replay sstables via nodetool upgradesstables if versions mismatch"],"exampleFix":"// before\nlong encoded = reader.readUnsignedVInt();\nint missing = (int) encoded; // may exceed superset, corrupt mask built silently\n// after\nif (encoded > supersetCount)\n    throw new IOException(\"Invalid large Columns subset: missing count \" + encoded + \" of \" + supersetCount);\nint missing = (int) encoded;","handlingStrategy":"try-catch","validationCode":"long encoded = dataReader.readUnsignedVInt();\nif (encoded > rowColumns.size())\n    throw new IOException(\"corrupt large columns subset: \" + encoded);","typeGuard":null,"tryCatchPattern":"try {\n    readLargeColumnsSubset(reader);\n} catch (IOException e) {\n    // mark table corrupt, run scrub/repair from replicas\n}","preventionTips":["Run scrub after any suspected unclean shutdown or storage failure","Keep replicas repaired (nodetool repair) so corrupt local data is recoverable","Alert on any 'Invalid ... Columns subset' log lines — they indicate storage corruption, not a code bug"],"tags":["cassandra","sstable","corruption","deserialization"],"backgroundTag":"corrupt-sstable-data","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}