apache/cassandra · error · InvalidRequestException

Cannot create materialized view

Error message

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.

What it means

gc_grace_seconds controls how long deleted/tombstoned data is retained so MV update batches can still be delivered to the view. If the base table sets it to 0, undelivered MV updates can be garbage-collected before replay, silently losing view rows. Cassandra refuses to create such a view because it would be incorrect.

Solutions

  1. ALTER TABLE <base> WITH gc_grace_seconds = 864000 (default) or another non-zero value before creating the view
  2. If zero is truly required, do not use materialized views on that table; maintain denormalized data in application code
  3. Re-create the base table with a proper gc_grace_seconds if the property was set by mistake

Example fix

// before
CREATE TABLE base (...) WITH gc_grace_seconds = 0;
CREATE MATERIALIZED VIEW mv AS SELECT ... FROM base ...;
// after
ALTER TABLE base WITH gc_grace_seconds = 864000;
CREATE MATERIALIZED VIEW mv AS SELECT ... FROM base ...;
Defensive patterns

Strategy: validation

Validate before calling

long ggs = baseTable.params.gcGraceSeconds; if (ggs == 0) throw new IllegalStateException("Set gc_grace_seconds > 0 before creating an MV on " + baseTable);

Try / catch

try { session.execute("ALTER TABLE base WITH gc_grace_seconds = 864000"); session.execute(createMvStmt); } catch (InvalidQueryException e) { /* inspect gc_grace_seconds message */ }

Prevention

When it happens

Trigger: CREATE MATERIALIZED VIEW on a base table whose table params have gc_grace_seconds == 0 (commonly set with WITH gc_grace_seconds = 0 in CREATE TABLE or ALTER TABLE).

Common situations: Tables tuned for pure time-series workloads with no deletes where operators set gc_grace_seconds=0 for compaction performance; users then add an MV on top and hit this wall.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

        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.",
                      viewName, tableName);
        }

        if (table.params.pendingDrop)
            throw ire("Cannot create materialized view '%s' for base table " +
                      "'%s' as it is being dropped.",
                      viewName, tableName);

        /*
         * Process SELECT clause
         */

        Set<ColumnIdentifier> selectedColumns = new HashSet<>();

View on GitHub (pinned to 88fd0f6a0e)