{"record":{"id":"bc515f7a4980b034","repo":"apache/cassandra","slug":"cannot-include-more-than-one-non-primary-key-colum","errorCode":null,"errorMessage":"Cannot include more than one non-primary key column in materialized view primary key (got %s)","messagePattern":"Cannot include more than one non-primary key column in materialized view primary key \\(got (.+?)\\)","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java","lineNumber":292,"sourceCode":"         * overwrite values in the view. We cannot support \"collapsing\" the base table into a smaller number of rows in\n         * the view because if we need to generate a tombstone, we have no way of knowing which value is currently being\n         * used in the view and whether or not to generate a tombstone. In order to not surprise our users, we require\n         * that they include all of the columns. We provide them with a list of all of the columns left to include.\n         */\n        List<ColumnIdentifier> missingPrimaryKeyColumns =\n            Lists.newArrayList(filter(transform(table.primaryKeyColumns(), c -> c.name), c -> !primaryKeyColumns.contains(c)));\n\n        if (!missingPrimaryKeyColumns.isEmpty())\n        {\n            throw ire(\"Cannot create materialized view '%s' without primary key columns %s from base table '%s'\",\n                      viewName, join(\", \", transform(missingPrimaryKeyColumns, ColumnIdentifier::toString)), tableName);\n        }\n\n        Set<ColumnIdentifier> regularBaseTableColumnsInViewPrimaryKey = new HashSet<>(primaryKeyColumns);\n        transform(table.primaryKeyColumns(), c -> c.name).forEach(regularBaseTableColumnsInViewPrimaryKey::remove);\n        if (regularBaseTableColumnsInViewPrimaryKey.size() > 1)\n        {\n            throw ire(\"Cannot include more than one non-primary key column in materialized view primary key (got %s)\",\n                      join(\", \", transform(regularBaseTableColumnsInViewPrimaryKey, ColumnIdentifier::toString)));\n        }\n\n        /*\n         * Process WHERE clause\n         */\n        if (whereClause.containsTokenRelations())\n            throw new InvalidRequestException(\"Cannot use token relation when defining a materialized view\");\n\n        if (whereClause.containsCustomExpressions())\n            throw ire(\"WHERE clause for materialized view '%s' cannot contain custom index expressions\", viewName);\n\n        StatementRestrictions restrictions =\n            new StatementRestrictions(state,\n                                      StatementType.SELECT,\n                                      table,\n                                      IndexHints.NONE,\n                                      whereClause,","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java#L274-L310","documentation":"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.","triggerScenarios":"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.","commonSituations":"Users try to key a view by two regular base columns (e.g. email and status) to create alternative lookup dimensions.","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."],"exampleFix":"// before\nCREATE MATERIALIZED VIEW mv AS SELECT id, email, status FROM t PRIMARY KEY (id, email, status);\n// after\nCREATE MATERIALIZED VIEW mv AS SELECT id, email FROM t PRIMARY KEY (id, email);","handlingStrategy":"validation","validationCode":"if (whereRestrictions.stream().noneMatch(r -> r.matches(\"\" + ck + \" IS NOT NULL\"))) throw new IllegalArgumentException(\"Restrict view clustering column: \" + ck);","typeGuard":null,"tryCatchPattern":"try { session.execute(createMvStmt); } catch (InvalidQueryException e) { if (e.getMessage().contains(\"must be restricted\")) { /* add the IS NOT NULL restriction */ } }","preventionTips":["Pair every view clustering column with an IS NOT NULL restriction","Review generated MV DDL for completeness of WHERE clauses"],"tags":["cassandra","cql","materialized-view","primary-key"],"backgroundTag":"schema-validation-failed","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}