apache/cassandra · error · InvalidRequestException

Materialized views cannot be created against other…

Error message

Materialized views cannot be created against other materialized views

What it means

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.

Solutions

  1. Create the new materialized view directly from the underlying base table, adding the needed WHERE restrictions on base partition-key columns
  2. Use a regular table plus application-side or SASI/SAI secondary indexing instead of chained views
  3. Denormalize into a second base table maintained by application logic if multi-level filtering is needed

Example fix

// before
CREATE MATERIALIZED VIEW keyspace.mv2 AS SELECT * FROM keyspace.mv1 WHERE ...;
// after
CREATE MATERIALIZED VIEW keyspace.mv2 AS SELECT * FROM keyspace.base_table WHERE ...;
Defensive patterns

Strategy: validation

Validate before calling

if (baseTableMetadata != null && baseTableMetadata.isView()) throw new IllegalArgumentException("Base table is a materialized view; MVs cannot chain");

Type guard

boolean isBaseTable(TableMetadata t) { return t != null && !t.isView(); }

Try / catch

try { session.execute(createMvStmt); } catch (InvalidQueryException e) { if (e.getMessage().contains("cannot be created against other materialized views")) { /* fall back to base table */ } }

Prevention

When it happens

Trigger: Executing CREATE MATERIALIZED VIEW ... AS SELECT ... FROM <another_materialized_view> in apply() when TableMetadata.isView() is true.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/e4927ac0d3136f52. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java:176

            throw ire("Cannot create materialized view '%s' - a table with the same name already exists", viewName);

        if (keyspace.hasView(viewName))
        {
            if (ifNotExists)
                return schema;

            throw new AlreadyExistsException(keyspaceName, viewName);
        }

        /*
         * Base table validation
         */

        if (table.isCounter())
            throw ire("Materialized views are not supported on counter tables");

        if (table.isView())
            throw ire("Materialized views cannot be created against other materialized views");

        // Guardrails on table properties
        Guardrails.tableProperties.guard(attrs.updatedProperties(), attrs::removeProperty, state);

        // Guardrail to limit number of mvs per table
        Iterable<ViewMetadata> tableViews = keyspace.views.forTable(table.id);
        Guardrails.materializedViewsPerTable.guard(Iterables.size(tableViews) + 1,
                                                   String.format("%s on table %s", viewName, table.name),
                                                   false,
                                                   state);

        if (table.params.gcGraceSeconds == 0)
        {
            throw ire("Cannot create materialized view '%s' for base table " +
                      "'%s' with gc_grace_seconds of 0, since this value is " +
                      "used to TTL undelivered updates. Setting gc_grace_seconds" +
                      " too low might cause undelivered updates to expire " +
                      "before being replayed.",

View on GitHub (pinned to 88fd0f6a0e)