{"record":{"id":"bee9d5d93eedbe7f","repo":"apache/cassandra","slug":"clustering-key-columns-must-exactly-match-columns","errorCode":null,"errorMessage":"Clustering key columns must exactly match columns in CLUSTERING ORDER BY directive","messagePattern":"Clustering key columns must exactly match columns in CLUSTERING ORDER BY directive","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java","lineNumber":270,"sourceCode":"\n            if (type.isMultiCell())\n            {\n                if (type.isCollection())\n                    throw ire(\"Invalid non-frozen collection type '%s' for PRIMARY KEY column '%s'\", type, name);\n                else\n                    throw ire(\"Invalid non-frozen user-defined type '%s' for PRIMARY KEY column '%s'\", type, name);\n            }\n\n            if (type.isCounter())\n                throw ire(\"counter type is not supported for PRIMARY KEY column '%s'\", name);\n\n            if (type.referencesDuration())\n                throw ire(\"duration type is not supported for PRIMARY KEY column '%s'\", name);\n        });\n\n        // If we give a clustering order, we must explicitly do so for all aliases and in the order of the PK\n        if (!clusteringOrder.isEmpty() && !clusteringColumns.equals(new ArrayList<>(clusteringOrder.keySet())))\n            throw ire(\"Clustering key columns must exactly match columns in CLUSTERING ORDER BY directive\");\n\n        /*\n         * We need to include all of the primary key columns from the base table in order to make sure that we do not\n         * 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);","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java#L252-L288","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nCREATE MATERIALIZED VIEW mv AS SELECT pk, ck, v FROM base WHERE pk IS NOT NULL PRIMARY KEY (pk, ck);\n// after\nCREATE MATERIALIZED VIEW mv AS SELECT pk, ck, v FROM base WHERE pk IS NOT NULL AND ck IS NOT NULL PRIMARY KEY (pk, ck);","handlingStrategy":"validation","validationCode":"for (String ck : viewClusteringCols) if (!whereRestrictions.contains(ck + \" IS NOT NULL\")) throw new IllegalArgumentException(\"Missing IS NOT NULL for clustering column: \" + ck);","typeGuard":null,"tryCatchPattern":"try { session.execute(createMvStmt); } catch (InvalidQueryException e) { if (e.getMessage().contains(\"IS NOT NULL\")) { /* add missing restrictions */ } }","preventionTips":["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"],"tags":["cql","materialized-view","clustering-key","where-clause"],"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-14T16:17:12.679Z"}