apache/cassandra · error · InvalidRequestException
Cannot include more than one non-primary key column in…
Error message
Cannot include more than one non-primary key column in materialized view primary key (got %s)
What it means
A view primary key may contain at most one base-table column that is not itself a base primary key column. Allowing multiple regular columns in the view key would require Cassandra to rewrite rows on any update of those columns, which is unsafe; only one such column is permitted.
Solutions
- Keep at most one regular base column in the view's primary key.
- Promote additional needed key columns to the base table's primary key.
- Create separate materialized views, each keyed by a single regular column, or maintain additional tables in application logic.
Example fix
// before CREATE MATERIALIZED VIEW mv AS SELECT id, email, status FROM t PRIMARY KEY (id, email, status); // after CREATE MATERIALIZED VIEW mv AS SELECT id, email FROM t PRIMARY KEY (id, email);
Defensive patterns
Strategy: validation
Validate before calling
if (whereRestrictions.stream().noneMatch(r -> r.matches("" + ck + " IS NOT NULL"))) throw new IllegalArgumentException("Restrict view clustering column: " + ck); Try / catch
try { session.execute(createMvStmt); } catch (InvalidQueryException e) { if (e.getMessage().contains("must be restricted")) { /* add the IS NOT NULL restriction */ } } Prevention
- Pair every view clustering column with an IS NOT NULL restriction
- Review generated MV DDL for completeness of WHERE clauses
When it happens
Trigger: CREATE MATERIALIZED VIEW ... PRIMARY KEY (base_pk_cols..., reg_col_a, reg_col_b) where both reg_col_a and reg_col_b are non-primary-key columns of the base table.
Common situations: Users try to key a view by two regular base columns (e.g. email and status) to create alternative lookup dimensions.
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
- ACCESS TO DATACENTERS operations not supported by…
- Cannot alter gc_grace_seconds of a materialized view to 0…
- Cannot alter gc_grace_seconds of the base table of a…
- Cannot set default_time_to_live for a materialized view…
- Cannot use ALTER TABLE on a materialized view; use ALTER…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/bc515f7a4980b034.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java:292
* 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);
transform(table.primaryKeyColumns(), c -> c.name).forEach(regularBaseTableColumnsInViewPrimaryKey::remove);
if (regularBaseTableColumnsInViewPrimaryKey.size() > 1)
{
throw ire("Cannot include more than one non-primary key column in materialized view primary key (got %s)",
join(", ", transform(regularBaseTableColumnsInViewPrimaryKey, ColumnIdentifier::toString)));
}
/*
* Process WHERE clause
*/
if (whereClause.containsTokenRelations())
throw new InvalidRequestException("Cannot use token relation when defining a materialized view");
if (whereClause.containsCustomExpressions())
throw ire("WHERE clause for materialized view '%s' cannot contain custom index expressions", viewName);
StatementRestrictions restrictions =
new StatementRestrictions(state,
StatementType.SELECT,
table,
IndexHints.NONE,
whereClause,View on GitHub (pinned to 88fd0f6a0e)