apache/cassandra · error · InvalidRequestException
Cannot create materialized view
Error message
Cannot create materialized view '%s' for base table '%s' as it is being dropped.
What it means
The statement checks whether the base table is marked pendingDrop in the schema at apply time. If a concurrent DROP TABLE committed between statement preparation and schema application, creating a view against it would produce an orphaned view, so it is rejected.
Solutions
- Re-run CREATE MATERIALIZED VIEW after confirming the base table exists and the drop was unintended
- If the drop was intentional, skip creating the view and remove it from migration scripts
- Serialize schema changes (e.g. run migrations under a schema-agreement guard) to avoid the race
Example fix
// before // DROP TABLE base; (issued concurrently) CREATE MATERIALIZED VIEW mv AS SELECT ... FROM base ...; // after // ensure base table exists and no concurrent DROP is running DESCRIBE KEYSPACE keyspace; -- confirm base table present CREATE MATERIALIZED VIEW mv AS SELECT ... FROM base ...;
Defensive patterns
Strategy: retry
Validate before calling
// check schema agreement before applying
if (!schemaContainsTable(keyspace, tableName)) throw new IllegalStateException("Base table missing; cannot create MV"); Try / catch
try { session.execute(createMvStmt); } catch (InvalidQueryException e) { if (e.getMessage().contains("being dropped")) { /* re-check table existence, retry if drop was not intended */ } } Prevention
- Serialize schema migrations; avoid concurrent DROP TABLE and CREATE MV on the same table
- Use schema-agreement checks in migration tooling before DDL
When it happens
Trigger: CREATE MATERIALIZED VIEW racing with DROP TABLE (or ALTER TABLE DROP that triggers a drop) on the same base table; the schema mutation applies after the drop is committed.
Common situations: Concurrent schema-change tooling (migration scripts, orchestrators) dropping tables while other sessions create dependent views; race is rare but possible in CI or hot schema-iteration environments.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- 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…
- Cannot alter gc_grace_seconds of a materialized view to 0…
- Cannot alter gc_grace_seconds of the base table of a…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/708d2fc91c0c5068.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/CreateViewStatement.java:199
// 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<>();
if (rawColumns.isEmpty()) // SELECT *
table.columns().forEach(c -> selectedColumns.add(c.name));
rawColumns.forEach(selector ->
{
if (null != selector.alias)
throw ire("Cannot use aliases when defining a materialized view (got %s)", selector);
if (!(selector.selectable instanceof Selectable.RawIdentifier))View on GitHub (pinned to 88fd0f6a0e)