apache/cassandra · error · InvalidRequestException
Clustering key columns must exactly match columns in…
Error message
Clustering key columns must exactly match columns in CLUSTERING ORDER BY directive
What it means
Clustering key columns of a materialized view must be restricted by IS NOT NULL in the view definition's WHERE clause. A NULL clustering value cannot exist as a view row (the key must be fully bound), so validation requires an explicit non-null restriction for each clustering column.
Solutions
- Add IS NOT NULL restrictions in WHERE for every clustering column in the view's primary key
- Verify all key columns appear in both the SELECT list and WHERE IS NOT NULL clauses before applying
Example fix
// before CREATE MATERIALIZED VIEW mv AS SELECT pk, ck, v FROM base WHERE pk IS NOT NULL PRIMARY KEY (pk, ck); // after CREATE MATERIALIZED VIEW mv AS SELECT pk, ck, v FROM base WHERE pk IS NOT NULL AND ck IS NOT NULL PRIMARY KEY (pk, ck);
Defensive patterns
Strategy: validation
Validate before calling
for (String ck : viewClusteringCols) if (!whereRestrictions.contains(ck + " IS NOT NULL")) throw new IllegalArgumentException("Missing IS NOT NULL for clustering column: " + ck); Try / catch
try { session.execute(createMvStmt); } catch (InvalidQueryException e) { if (e.getMessage().contains("IS NOT NULL")) { /* add missing restrictions */ } } Prevention
- Always append IS NOT NULL for every key column in MV WHERE clauses
- Generate WHERE restrictions together with the PRIMARY KEY clause to avoid drift
When it happens
Trigger: CREATE MATERIALIZED VIEW ... WHERE pk IS NOT NULL PRIMARY KEY (pk, ck) where ck (a view clustering column) has no 'ck IS NOT NULL' restriction.
Common situations: Only restricting the partition key and forgetting clustering columns; dropping one of several IS NOT NULL clauses when editing the view definition; generated DDL omitting a restriction.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Cannot create materialized view
- Primary key columns must be restricted with 'IS NOT NULL'…
- ACCESS TO DATACENTERS operations not supported by…
- Aggregation function are not supported in the where clause
- Bind variables are not allowed in CREATE MATERIALIZED VIEW…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/bee9d5d93eedbe7f.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java:270
if (type.isMultiCell())
{
if (type.isCollection())
throw ire("Invalid non-frozen collection type '%s' for PRIMARY KEY column '%s'", type, name);
else
throw ire("Invalid non-frozen user-defined type '%s' for PRIMARY KEY column '%s'", type, name);
}
if (type.isCounter())
throw ire("counter type is not supported for PRIMARY KEY column '%s'", name);
if (type.referencesDuration())
throw ire("duration type is not supported for PRIMARY KEY column '%s'", name);
});
// If we give a clustering order, we must explicitly do so for all aliases and in the order of the PK
if (!clusteringOrder.isEmpty() && !clusteringColumns.equals(new ArrayList<>(clusteringOrder.keySet())))
throw ire("Clustering key columns must exactly match columns in CLUSTERING ORDER BY directive");
/*
* We need to include all of the primary key columns from the base table in order to make sure that we do not
* overwrite values in the view. We cannot support "collapsing" the base table into a smaller number of rows in
* the view because if we need to generate a tombstone, we have no way of knowing which value is currently being
* used in the view and whether or not to generate a tombstone. In order to not surprise our users, we require
* that they include all of the columns. We provide them with a list of all of the columns left to include.
*/
List<ColumnIdentifier> missingPrimaryKeyColumns =
Lists.newArrayList(filter(transform(table.primaryKeyColumns(), c -> c.name), c -> !primaryKeyColumns.contains(c)));
if (!missingPrimaryKeyColumns.isEmpty())
{
throw ire("Cannot create materialized view '%s' without primary key columns %s from base table '%s'",
viewName, join(", ", transform(missingPrimaryKeyColumns, ColumnIdentifier::toString)), tableName);
}
Set<ColumnIdentifier> regularBaseTableColumnsInViewPrimaryKey = new HashSet<>(primaryKeyColumns);View on GitHub (pinned to 88fd0f6a0e)