apache/cassandra · error · IOException

Term - ' ' belongs to more than keys in mode, which is not…

Error message

Term - '%s' belongs to more than %d keys in %s mode, which is not allowed.

What it means

SASI's OnDiskIndexBuilder refuses to build an index segment in SPARSE mode when a single term maps to more than MAX_KEYS_SPARSE keys. SPARSE mode uses a compact token-tree encoding that assumes low cardinality per term, so a term exceeding the key cap would produce an oversized, inefficient structure; the builder throws IOException instead of silently degrading the index format.

Solutions

  1. Remove the low-cardinality column from SASI indexing or index it with a different kind/mode so it is not built in SPARSE mode
  2. Reduce the number of rows sharing that term per index segment (smaller memtable/sstable, more frequent flushes)
  3. Check MAX_KEYS_SPARSE in OnDiskIndexBuilder and confirm no local modification lowered it below your data's cardinality
  4. Rebuild the affected SASI index after fixing the data or configuration

Example fix

// before
CREATE CUSTOM INDEX ON ks.tbl (status) USING 'org.apache.cassandra.index.sasi.SASIIndex';
// data has 10M rows with status='ACTIVE' -> SPARSE cap exceeded
// after
// drop and re-create without indexing the low-cardinality column, or use a regular (non-SASI) index:
CREATE INDEX ON ks.tbl (status);
Defensive patterns

Strategy: validation

Validate before calling

// Before creating a SASI index on a column, estimate per-term cardinality
cqlsh> SELECT COUNT(*) FROM ks.tbl WHERE status = 'ACTIVE';
// If counts per value approach MAX_KEYS_SPARSE, do not index in SPARSE mode.

Prevention

When it happens

Trigger: Calling OnDiskIndexBuilder.add() many times with the same term value (e.g. a boolean-like or low-cardinality column) in SPARSE mode, then calling build() so the term's TokenTreeBuilder exceeds MAX_KEYS_SPARSE keys when the segment is serialized.

Common situations: Indexing a low-cardinality column (status flags, booleans) where thousands of rows share one term; also happens when MAX_KEYS_SPARSE was reduced via config in custom builds and a previously-indexable column now exceeds the cap.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/index/sasi/disk/OnDiskIndexBuilder.java:621

        private final List<TokenTreeBuilder> containers = new ArrayList<>();
        private TokenTreeBuilder combinedIndex;

        public MutableDataBlock(AbstractType<?> comparator, Mode mode)
        {
            this.comparator = comparator;
            this.mode = mode;
            this.combinedIndex = initCombinedIndex();
        }

        protected void addInternal(InMemoryDataTerm term) throws IOException
        {
            TokenTreeBuilder keys = term.keys;

            if (mode == Mode.SPARSE)
            {
                if (keys.getTokenCount() > MAX_KEYS_SPARSE)
                    throw new IOException(String.format("Term - '%s' belongs to more than %d keys in %s mode, which is not allowed.",
                                                        comparator.getString(term.term.getBytes()), MAX_KEYS_SPARSE, mode.name()));

                writeTerm(term, keys);
            }
            else
            {
                writeTerm(term, offset);

                offset += keys.serializedSize();
                containers.add(keys);
            }

            if (mode == Mode.SPARSE)
                combinedIndex.add(keys);
        }

        protected int sizeAfter(InMemoryDataTerm element)
        {

View on GitHub (pinned to 88fd0f6a0e)