{"record":{"id":"e4927ac0d3136f52","repo":"apache/cassandra","slug":"materialized-views-cannot-be-created-against-other","errorCode":null,"errorMessage":"Materialized views cannot be created against other materialized views","messagePattern":"Materialized views cannot be created against other materialized views","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java","lineNumber":176,"sourceCode":"            throw ire(\"Cannot create materialized view '%s' - a table with the same name already exists\", viewName);\n\n        if (keyspace.hasView(viewName))\n        {\n            if (ifNotExists)\n                return schema;\n\n            throw new AlreadyExistsException(keyspaceName, viewName);\n        }\n\n        /*\n         * Base table validation\n         */\n\n        if (table.isCounter())\n            throw ire(\"Materialized views are not supported on counter tables\");\n\n        if (table.isView())\n            throw ire(\"Materialized views cannot be created against other materialized views\");\n\n        // Guardrails on table properties\n        Guardrails.tableProperties.guard(attrs.updatedProperties(), attrs::removeProperty, state);\n\n        // Guardrail to limit number of mvs per table\n        Iterable<ViewMetadata> tableViews = keyspace.views.forTable(table.id);\n        Guardrails.materializedViewsPerTable.guard(Iterables.size(tableViews) + 1,\n                                                   String.format(\"%s on table %s\", viewName, table.name),\n                                                   false,\n                                                   state);\n\n        if (table.params.gcGraceSeconds == 0)\n        {\n            throw ire(\"Cannot create materialized view '%s' for base table \" +\n                      \"'%s' with gc_grace_seconds of 0, since this value is \" +\n                      \"used to TTL undelivered updates. Setting gc_grace_seconds\" +\n                      \" too low might cause undelivered updates to expire \" +\n                      \"before being replayed.\",","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java#L158-L194","documentation":"Cassandra materialized views are built from a base table, and the view itself is stored internally as a table. Chaining a materialized view on top of another materialized view is unsupported because updates would need to cascade between views, which the implementation does not guarantee. The schema service rejects this during CREATE MATERIALIZED VIEW validation.","triggerScenarios":"Executing CREATE MATERIALIZED VIEW ... AS SELECT ... FROM <another_materialized_view> in apply() when TableMetadata.isView() is true.","commonSituations":"Developers assume views compose like relational databases (e.g. building a filtered/aggregate view from an existing MV); porting SQL mental models to CQL; accidentally pointing at an internal view table name.","solutions":["Create the new materialized view directly from the underlying base table, adding the needed WHERE restrictions on base partition-key columns","Use a regular table plus application-side or SASI/SAI secondary indexing instead of chained views","Denormalize into a second base table maintained by application logic if multi-level filtering is needed"],"exampleFix":"// before\nCREATE MATERIALIZED VIEW keyspace.mv2 AS SELECT * FROM keyspace.mv1 WHERE ...;\n// after\nCREATE MATERIALIZED VIEW keyspace.mv2 AS SELECT * FROM keyspace.base_table WHERE ...;","handlingStrategy":"validation","validationCode":"if (baseTableMetadata != null && baseTableMetadata.isView()) throw new IllegalArgumentException(\"Base table is a materialized view; MVs cannot chain\");","typeGuard":"boolean isBaseTable(TableMetadata t) { return t != null && !t.isView(); }","tryCatchPattern":"try { session.execute(createMvStmt); } catch (InvalidQueryException e) { if (e.getMessage().contains(\"cannot be created against other materialized views\")) { /* fall back to base table */ } }","preventionTips":["Always resolve the MV's FROM target to a real base table, not an internal view table","Treat MVs as non-composable; plan denormalization with base tables only"],"tags":["cql","materialized-view","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}