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
- ALTER TABLE <base> WITH gc_grace_seconds = 864000 (default) or another non-zero value before creating the view
- If zero is truly required, do not use materialized views on that table; maintain denormalized data in application code
- 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
- Keep gc_grace_seconds at its default (864000) on any table that has MVs
- Document that gc_grace_seconds=0 tuning is incompatible with MVs
- Check table params in system_schema.tables before provisioning MVs
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
- Cannot alter gc_grace_seconds of a materialized view to 0…
- Cannot alter gc_grace_seconds of the base table of a…
- ACCESS TO DATACENTERS operations not supported by…
- Bind variables are not allowed in CREATE MATERIALIZED VIEW…
- Can only select columns by name when defining a…
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)