apache/cassandra · error · InvalidRequestException

Cannot set default_time_to_live for a materialized view. Dat

Error message

Cannot set default_time_to_live for a materialized view. Data in a materialized view always expire at the same time than the corresponding data in the parent table.

What it means

default_time_to_live cannot be set on a materialized view. View rows are derived from base rows and must expire exactly when the corresponding base data expires; an independent TTL would create inconsistencies between base table and view.

Source

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

        // See CASSANDRA-13798
        Set<ColumnMetadata> restrictedNonPrimaryKeyColumns = restrictions.nonPKRestrictedColumns(false);
        if (!restrictedNonPrimaryKeyColumns.isEmpty() && !MV_ALLOW_FILTERING_NONKEY_COLUMNS_UNSAFE.getBoolean())
        {
            throw ire("Non-primary key columns can only be restricted with 'IS NOT NULL' (got: %s restricted illegally)",
                      join(",", transform(restrictedNonPrimaryKeyColumns, ColumnMetadata::toString)));
        }

        /*
         * Validate WITH params
         */

        attrs.validate();

        if (attrs.hasOption(TableParams.Option.DEFAULT_TIME_TO_LIVE)
            && attrs.getInt(TableParams.Option.DEFAULT_TIME_TO_LIVE.toString(), 0) != 0)
        {
            throw ire("Cannot set default_time_to_live for a materialized view. " +
                      "Data in a materialized view always expire at the same time than " +
                      "the corresponding data in the parent table.");
        }

        /*
         * Build the thing
         */

        TableMetadata.Builder builder = TableMetadata.builder(keyspaceName, viewName);

        if (attrs.hasProperty(TableAttributes.ID))
            builder.id(attrs.getId());
        else if (!builder.hasId())
            builder.id(TableId.get(metadata));

        builder.params(attrs.asNewTableParams(keyspaceName))
               .kind(TableMetadata.Kind.VIEW);

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Remove default_time_to_live from the view's WITH options.
  2. Set default_time_to_live on the BASE table; view data will expire with the base data.
  3. Use per-insert TTLs on base writes; they propagate to view rows automatically.

Example fix

// before
CREATE MATERIALIZED VIEW mv AS SELECT ... PRIMARY KEY (...) WITH default_time_to_live = 86400;
// after
CREATE MATERIALIZED VIEW mv AS SELECT ... PRIMARY KEY (...); // TTL comes from the base table
Defensive patterns

Strategy: validation

Validate before calling

if (viewOptions.containsKey("default_time_to_live") && !viewOptions.get("default_time_to_live").equals("0"))
    throw new IllegalArgumentException("do not set default_time_to_live on a materialized view");

Prevention

When it happens

Trigger: CREATE MATERIALIZED VIEW ... WITH default_time_to_live = N where N != 0.

Common situations: Users copy table WITH options (including default_time_to_live) onto a view definition, expecting per-view TTL control.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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