apache/cassandra · error · InvalidRequestException
Forbidden default_time_to_live detected for a materialized v
Error message
Forbidden default_time_to_live detected for a materialized view. Data in a materialized view always expire at the same time than the corresponding data in the parent table. default_time_to_live must be set to zero, see CASSANDRA-12868 for more information
What it means
Materialized views must have default_time_to_live = 0 because view rows must expire at exactly the same time as the corresponding base-table rows; a view-level TTL would cause divergence (CASSANDRA-12868). AlterViewStatement.apply() throws when the altered params have defaultTimeToLive > 0.
Source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/AlterViewStatement.java:101
}
attrs.validate();
// Guardrails on table properties
Guardrails.tableProperties.guard(attrs.updatedProperties(), attrs::removeProperty, state);
TableParams params = attrs.asAlteredTableParams(view.metadata.params);
if (params.gcGraceSeconds == 0)
{
throw ire("Cannot alter gc_grace_seconds of a materialized view to 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.");
}
if (params.defaultTimeToLive > 0)
{
throw ire("Forbidden default_time_to_live detected for a materialized view. " +
"Data in a materialized view always expire at the same time than " +
"the corresponding data in the parent table. default_time_to_live " +
"must be set to zero, see CASSANDRA-12868 for more information");
}
ViewMetadata newView = view.copy(view.metadata.withSwapped(params));
return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.views.withSwapped(newView)));
}
SchemaChange schemaChangeEvent(KeyspacesDiff diff)
{
return new SchemaChange(Change.UPDATED, Target.TABLE, keyspaceName, viewName);
}
public void authorize(ClientState client)
{
ViewMetadata view = Schema.instance.getView(keyspaceName, viewName);
if (null != view)View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Remove the default_time_to_live option from the ALTER MATERIALIZED VIEW statement
- Set TTL on the base table instead (`ALTER TABLE ... WITH default_time_to_live = n` or per-row USING TTL), which propagates expiry to views
- Keep/force default_time_to_live = 0 on the view
Example fix
// before ALTER MATERIALIZED VIEW ks.v WITH default_time_to_live = 604800; // after ALTER TABLE ks.base WITH default_time_to_live = 604800;
Defensive patterns
Strategy: validation
Validate before calling
// Ensure no positive TTL is applied to views
if (Number(opts.default_time_to_live) > 0) {
throw new Error('default_time_to_live must be 0 for materialized views (CASSANDRA-12868)');
} Type guard
function isViewSafeTtl(s) { const n = Number(s); return Number.isFinite(n) && n === 0; } Try / catch
try {
session.execute(alterViewCql);
} catch (e) {
if (/Forbidden default_time_to_live/.test(e.message)) {
// move the TTL to the base table instead
} else throw e;
} Prevention
- Only set default_time_to_live on base tables, never views
- Set row TTL with USING TTL on writes to the base table
- Filter out TTL options in view-alteration builders
- Remember view expiry mirrors the base table by design
When it happens
Trigger: `ALTER MATERIALIZED VIEW <ks>.<view> WITH default_time_to_live = <n>` for any n > 0.
Common situations: Applying table-level TTL policies uniformly to views; attempting to 'fix' expiring data by adding TTL at the view level instead of the base table.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Cannot alter gc_grace_seconds of a materialized view to 0, s
- Cannot set default_time_to_live for a materialized view. Dat
- Load CIDR groups cache operation not supported by %s
- 'Get CIDR groups for IP' operation not supported by %s
- ACCESS TO DATACENTERS operations not supported by AllowAllNe
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/0d43213ec3d18fde.
Report an issue: GitHub.