apache/cassandra · error
All indexed columns should be included into the column…
Error message
All indexed columns should be included into the column slice, missing: ${column} What it means
Operation.localSatisfiedBy evaluates each indexed column of a column slice against a row. When allowMissingColumns is false, any indexed column whose value cannot be resolved (null from ColumnIndex.getValueOf) is treated as a broken plan invariant and throws IllegalStateException. The library assumes query planning guaranteed every indexed column is present in the slice being evaluated.
Solutions
- Run a full repair and rebuild the SASI index so all SSTables/rows contain the indexed column values
- Check schema agreement (SELECT * FROM system_schema.columns) and ensure all nodes agree the indexed column exists
- Ensure rows are rewritten (UPDATE setting the column) if pre-existing data predates the column addition
- If the query is intentionally tolerant of missing columns, verify the allowMissingColumns flag is set by the planner path you use
Example fix
// before cqlsh> SELECT * FROM ks.tbl WHERE age = 30 ALLOW FILTERING; // rows missing 'age' crash SASI plan eval // after cqlsh> ALTER TABLE ks.tbl DROP INDEX age_idx; cqlsh> ALTER TABLE ks.tbl ADD age int; -- ensure column exists before indexing cqlsh> CREATE CUSTOM INDEX age_idx ON ks.tbl (age) USING 'org.apache.cassandra.index.sasi.SASIIndex';
Defensive patterns
Strategy: try-catch
Validate before calling
cqlsh> SELECT column_name FROM system_schema.columns WHERE keyspace_name='ks' AND table_name='tbl'; -- confirm the indexed column exists and is populated in all rows before querying
Try / catch
try {
session.execute("SELECT * FROM ks.tbl WHERE age = ?", 30);
} catch (IllegalStateException e) {
// log plan inconsistency; trigger repair/index rebuild
scheduler.rebuildIndex("ks", "tbl");
} Prevention
- Add columns before creating SASI indexes on them; backfill values for existing rows first
- Keep the schema in agreement across nodes; check schema versions after DDL
- Run regular repairs so SSTables from different epochs stay consistent
When it happens
Trigger: Executing a SASI query whose plan includes multiple indexed columns where a row (or the static row for Kind.STATIC columns) is missing one of the indexed column values; the controller built the Operation without allowing missing columns, then satisfiedBy() reaches a row lacking a column value.
Common situations: Rows written before a column was added to the schema but after the SASI index was created; queries mixing regular and static indexed columns; legacy SSTables that don't contain the indexed column; schema disagreements between nodes.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Found 2 incompatible versions of column
- ACCESS TO DATACENTERS operations not supported by…
- Aggregate ' ' already exists
- All values must be either negative or positive, got
- ALREADY_EXISTS
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/797cecf790ddcfd6.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/index/sasi/plan/Operation.java:223
private boolean localSatisfiedBy(Unfiltered currentCluster, Row staticRow, boolean allowMissingColumns)
{
if (currentCluster == null || !currentCluster.isRow())
return false;
final long now = FBUtilities.nowInSeconds();
boolean result = false;
int idx = 0;
for (ColumnMetadata column : expressions.keySet())
{
if (column.kind == Kind.PARTITION_KEY)
continue;
ByteBuffer value = ColumnIndex.getValueOf(column, column.kind == Kind.STATIC ? staticRow : (Row) currentCluster, now);
boolean isMissingColumn = value == null;
if (!allowMissingColumns && isMissingColumn)
throw new IllegalStateException("All indexed columns should be included into the column slice, missing: " + column);
boolean isMatch = false;
// If there is a column with multiple expressions that effectively means an OR
// e.g. comment = 'x y z' could be split into 'comment' EQ 'x', 'comment' EQ 'y', 'comment' EQ 'z'
// by analyzer, in situation like that we only need to check if at least one of expressions matches,
// and there is no hit on the NOT_EQ (if any) which are always at the end of the filter list.
// Loop always starts from the end of the list, which makes it possible to break after the last
// NOT_EQ condition on first EQ/RANGE condition satisfied, instead of checking every
// single expression in the column filter list.
List<Expression> filters = expressions.get(column);
for (int i = filters.size() - 1; i >= 0; i--)
{
Expression expression = filters.get(i);
isMatch = !isMissingColumn && expression.isSatisfiedBy(value);
if (expression.getOp() == Op.NOT_EQ)
{
// since this is NOT_EQ operation we have to
// inverse match flag (to check against other expressions),View on GitHub (pinned to 88fd0f6a0e)