{"record":{"id":"831abc45b64ba159","repo":"apache/cassandra","slug":"cannot-alter-gc-grace-seconds-of-a-materialized-vi","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/AlterViewStatement.java","lineNumber":94,"sourceCode":"                          ? null\n                          : keyspace.views.getNullable(viewName);\n\n        if (null == view)\n        {\n            if (ifExists) return schema;\n            throw ire(\"Materialized view '%s.%s' doesn't exist\", keyspaceName, viewName);\n        }\n\n        attrs.validate();\n\n        // Guardrails on table properties\n        Guardrails.tableProperties.guard(attrs.updatedProperties(), attrs::removeProperty, state);\n\n        TableParams params = attrs.asAlteredTableParams(view.metadata.params);\n\n        if (params.gcGraceSeconds == 0)\n        {\n            throw ire(\"Cannot alter gc_grace_seconds of a materialized view to 0, since this \" +\n                      \"value is used to TTL undelivered updates. Setting gc_grace_seconds too \" +\n                      \"low might cause undelivered updates to expire before being replayed.\");\n        }\n\n        if (params.defaultTimeToLive > 0)\n        {\n            throw ire(\"Forbidden default_time_to_live detected for a materialized view. \" +\n                      \"Data in a materialized view always expire at the same time than \" +\n                      \"the corresponding data in the parent table. default_time_to_live \" +\n                      \"must be set to zero, see CASSANDRA-12868 for more information\");\n        }\n\n        ViewMetadata newView = view.copy(view.metadata.withSwapped(params));\n        return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.views.withSwapped(newView)));\n    }\n\n    SchemaChange schemaChangeEvent(KeyspacesDiff diff)\n    {","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/AlterViewStatement.java#L76-L112","documentation":"Cassandra refuses to set gc_grace_seconds to 0 on a materialized view because that value is used to TTL undelivered view updates; a too-low value lets pending updates expire before they can be replayed, causing view/base divergence. AlterViewStatement.apply() checks the computed TableParams after applying the ALTER VIEW options and throws if gcGraceSeconds == 0.","triggerScenarios":"`ALTER MATERIALIZED VIEW <ks>.<view> WITH gc_grace_seconds = 0` — or any alteration whose resulting params set gc_grace_seconds to 0.","commonSituations":"Copying table tuning params (like those used on tombstone-heavy base tables) onto views; scripts that blanket-apply gc_grace_seconds=0 across all tables and views.","solutions":["Set gc_grace_seconds to a positive value, e.g. `WITH gc_grace_seconds = 86400` (the default)","Exclude materialized views from any bulk gc_grace_seconds tuning script","If tombstone buildup is the concern, tune the base table and understand view update semantics rather than zeroing grace on the view"],"exampleFix":"// before\nALTER MATERIALIZED VIEW ks.v WITH gc_grace_seconds = 0;\n\n// after\nALTER MATERIALIZED VIEW ks.v WITH gc_grace_seconds = 86400;","handlingStrategy":"validation","validationCode":"// Parse the WITH options before sending\nif (opts.gc_grace_seconds === 0) {\n  throw new Error('gc_grace_seconds must be > 0 for materialized views');\n}","typeGuard":"function isSafeViewGcGrace(s) { const n = Number(s); return Number.isFinite(n) && n > 0; }","tryCatchPattern":"try {\n  session.execute(alterViewCql);\n} catch (e) {\n  if (/gc_grace_seconds of a materialized view to 0/.test(e.message)) {\n    // retry with a safe value, e.g. 86400\n  } else throw e;\n}","preventionTips":["Never blanket-apply gc_grace_seconds=0 across tables and views","Default materialized views to the standard 86400 grace seconds","Review view tuning options against guardrails before deploying","Keep base-table and view tuning scripts separate"],"tags":["cassandra","cql","materialized-view","guardrails","gc-grace-seconds"],"backgroundTag":"invalid-config-value","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}