apache/cassandra · error · IOException
Invalid large Columns subset: missing count ${encoded} of ${
Error message
Invalid large Columns subset: missing count ${encoded} of ${supersetCount} What it means
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).
Source
Thrown at src/java/org/apache/cassandra/io/sstable/UnfilteredDescriptor.java:190
// Mirrors the corruption check in Columns.Serializer.deserializeSubset.
if ((encoded >>> rowColumns.size()) != 0)
throw new IOException("Invalid Columns subset bytes; too many bits set: " + Long.toBinaryString(encoded));
missingColumnsMask = encoded;
}
/**
* Wire format per Columns.Serializer.serializeLargeSubset: an unsigned vint delta of
* supersetCount - presentCount, then one unsigned vint superset index per column. The indices
* name the present columns when presentCount is under half the superset, and the missing
* columns otherwise. Decoding into reusable mask words leaves rowColumns as the superset, so
* CellCursor never rebuilds its per-superset arrays.
*/
private void readLargeColumnsSubset(RandomAccessReader dataReader) throws IOException
{
long encoded = dataReader.readUnsignedVInt();
int supersetCount = rowColumns.size();
if (encoded > supersetCount)
throw new IOException("Invalid large Columns subset: missing count " + encoded + " of " + supersetCount);
int delta = (int) encoded;
int columnCount = supersetCount - delta;
int nWords = (supersetCount + 63) >>> 6;
if (presentColumnsWords == null || presentColumnsWords.length < nWords)
presentColumnsWords = new long[nWords];
if (columnCount < supersetCount / 2)
readPresentColumnIndexes(dataReader, supersetCount, nWords, columnCount);
else
readMissingColumnIndexes(dataReader, supersetCount, nWords, delta);
useColumnsWords = true;
missingColumnsMask = 0;
}
private void readPresentColumnIndexes(RandomAccessReader dataReader, int supersetCount, int nWords, int columnCount) throws IOException
{View on GitHub (pinned to 88fd0f6a0e)
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
Example fix
// before
long encoded = reader.readUnsignedVInt();
int missing = (int) encoded; // may exceed superset, corrupt mask built silently
// after
if (encoded > supersetCount)
throw new IOException("Invalid large Columns subset: missing count " + encoded + " of " + supersetCount);
int missing = (int) encoded; Defensive patterns
Strategy: try-catch
Validate before calling
long encoded = dataReader.readUnsignedVInt();
if (encoded > rowColumns.size())
throw new IOException("corrupt large columns subset: " + encoded); Try / catch
try {
readLargeColumnsSubset(reader);
} catch (IOException e) {
// mark table corrupt, run scrub/repair from replicas
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Corrupt flags value for clustering prefix (isStatic flag set
- Invalid Columns subset bytes; too many bits set: ${encoded}
- Unknown column <name> during deserialization
- Invalid Columns subset bytes; too many bits set:<encoded>
- Clustering block upper bits (those not associated with keys)
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/9131e3d3227a05b0.
Report an issue: GitHub.