{"record":{"id":"f4e33287e4a61bf3","repo":"apache/cassandra","slug":"cannot-alter-gc-grace-seconds-of-the-base-table-of","errorCode":null,"errorMessage":"Cannot alter gc_grace_seconds of the base table 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 the base table 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/AlterTableStatement.java","lineNumber":696,"sourceCode":"\n        @Override\n        public boolean compatibleWith(ClusterMetadata metadata)\n        {\n            return metadata.directory.commonSerializationVersion.isAtLeast(Version.V0);\n        }\n\n        public KeyspaceMetadata apply(Epoch epoch, KeyspaceMetadata keyspace, TableMetadata table, ClusterMetadata metadata)\n        {\n            attrs.validate();\n\n            TableParams params = attrs.asAlteredTableParams(table.params);\n\n            if (table.isCounter() && params.defaultTimeToLive > 0)\n                throw ire(\"Cannot set default_time_to_live on a table with counters\");\n\n            if (!isEmpty(keyspace.views.forTable(table.id)) && params.gcGraceSeconds == 0)\n            {\n                throw ire(\"Cannot alter gc_grace_seconds of the base table of a \" +\n                          \"materialized view to 0, since this value is used to TTL \" +\n                          \"undelivered updates. Setting gc_grace_seconds too low might \" +\n                          \"cause undelivered updates to expire \" +\n                          \"before being replayed.\");\n            }\n\n            if (keyspace.replicationStrategy.hasTransientReplicas()\n                && params.readRepair != ReadRepairStrategy.NONE)\n            {\n                throw ire(\"read_repair must be set to 'NONE' for transiently replicated keyspaces\");\n            }\n\n            if (!params.compression.isEnabled())\n                Guardrails.uncompressedTablesEnabled.ensureEnabled(state);\n\n            params = validateAndUpdateTransactionalMigration(table.isCounter(), table.params, params);\n\n            return keyspace.withSwapped(keyspace.tables.withSwapped(table.withSwapped(params)));","sourceCodeStart":678,"sourceCodeEnd":714,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java#L678-L714","documentation":"The base table of a materialized view must keep a nonzero gc_grace_seconds, because that value TTLs undelivered view updates; setting it to 0 can cause undelivered updates to expire before being replayed, silently desynchronizing the view. AlterTableStatement.apply (line 696) throws this InvalidRequest when the keyspace has views for the table and params.gcGraceSeconds == 0.","triggerScenarios":"ALTER TABLE base_table WITH gc_grace_seconds = 0; where keyspace.views.forTable(table.id) is non-empty (the table has at least one materialized view).","commonSituations":"Operators tightening gc_grace_seconds for storage or compaction reasons on a table that quietly has MVs; copied tuning scripts applied to all tables.","solutions":["Keep gc_grace_seconds > 0 on the base table (default 10 days; lower but non-zero if storage is a concern)","Drop the materialized views before setting gc_grace_seconds = 0, if zero is truly required","Audit which tables have MVs via system_schema.views before tuning gc_grace_seconds"],"exampleFix":"// before\nALTER TABLE orders WITH gc_grace_seconds = 0;\n// after\nALTER TABLE orders WITH gc_grace_seconds = 86400; // keep non-zero for MV base table","handlingStrategy":"validation","validationCode":"boolean hasViews = !session.execute(\"SELECT view_name FROM system_schema.views WHERE keyspace_name=? AND base_table_id=\" , ks).all().isEmpty(); // or keyspace.views.forTable(tableId); if (hasViews && params.gcGraceSeconds == 0) { /* reject or raise gc_grace_seconds */ }","typeGuard":null,"tryCatchPattern":"try { session.execute(alterStmt); } catch (InvalidRequestException e) { if (e.getMessage().contains(\"Cannot alter gc_grace_seconds of the base table of a materialized view\")) { /* keep a positive gc_grace_seconds or drop views first */ } else throw e; }","preventionTips":["Check system_schema.views before tuning gc_grace_seconds on any table","Keep gc_grace_seconds well above expected repair intervals for MV base tables","Exclude MV base tables from aggressive gc_grace_seconds tuning scripts"],"tags":["cassandra","cql","materialized-view","gc-grace-seconds","schema"],"backgroundTag":"conflicting-config-options","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"}