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

  1. Keep at most one regular base column in the view's primary key.
  2. Promote additional needed key columns to the base table's primary key.
  3. 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

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


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)