{"record":{"id":"448570631f4522d8","repo":"apache/cassandra","slug":"cannot-re-add-previously-dropped-counter-column-s","errorCode":null,"errorMessage":"Cannot re-add previously dropped counter column %s","messagePattern":"Cannot re-add previously dropped counter column (.+?)","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java","lineNumber":403,"sourceCode":"                {\n                    throw ire(\"Cannot add a column '%s' of type %s, incompatible with previously dropped column '%s' of type %s\",\n                              name,\n                              type.asCQL3Type(),\n                              name,\n                              droppedColumn.type.asCQL3Type());\n                }\n\n                if (droppedColumn.isStatic() != isStatic)\n                {\n                    throw ire(\"Cannot re-add previously dropped column '%s' of kind %s, incompatible with previous kind %s\",\n                              name,\n                              isStatic ? ColumnMetadata.Kind.STATIC : ColumnMetadata.Kind.REGULAR,\n                              droppedColumn.kind);\n                }\n\n                // Cannot re-add a dropped counter column. See #7831.\n                if (table.isCounter())\n                    throw ire(\"Cannot re-add previously dropped counter column %s\", name);\n            }\n\n            if (isStatic)\n                tableBuilder.addStaticColumn(name, type, mask, columnConstraints);\n            else\n                tableBuilder.addRegularColumn(name, type, mask, columnConstraints);\n\n            if (!isStatic)\n            {\n                for (ViewMetadata view : keyspace.views.forTable(table.id))\n                {\n                    if (view.includeAllColumns)\n                    {\n                        ColumnMetadata viewColumn = ColumnMetadata.regularColumn(view.metadata, name.bytes, type, ColumnMetadata.NO_UNIQUE_ID)\n                                                                  .withNewMask(mask)\n                                                                  .withNewColumnConstraints(columnConstraints);\n                        viewsBuilder.put(viewsBuilder.get(view.name()).withAddedRegularColumn(viewColumn));\n                    }","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java#L385-L421","documentation":"In a counter table, a dropped counter column cannot be re-added under the same name (CASSANDRA-7831). Counter increments are timestamped deltas; after a drop, re-adding the same name would let stale/deleted counter deltas be re-applied, producing incorrect totals. Cassandra rejects this outright at ALTER TABLE time.","triggerScenarios":"On a table created WITH COUNTERS (or containing counter columns), execute ALTER TABLE t DROP c; followed by ALTER TABLE t ADD c counter; — table.isCounter() is true and a dropped column with that name exists.","commonSituations":"Attempting to 'reset' a counter by dropping and re-adding the column; schema-sync tools replaying a drop+add history on counter tables; restoring an old schema script that drops and re-adds counter columns.","solutions":["Use a new column name for the counter: ALTER TABLE t ADD c2 counter; and read/write the new counter.","Reset a counter in place with an UPDATE ... SET c = c - <value> rather than dropping/re-adding.","Migrate to a new counter table (counters are stored per-cell in a dedicated table) if a clean layout is required.","Recreate the table (with data migration for non-counter data is not possible for counters; write fresh counters) to clear the dropped-column record."],"exampleFix":"// before\nALTER TABLE metrics DROP hits;\nALTER TABLE metrics ADD hits counter;   -- fails (CASSANDRA-7831)\n// after\nALTER TABLE metrics ADD hits_v2 counter;\n-- or reset in place before dropping: UPDATE metrics SET hits = hits - <current> WHERE key = ...;","handlingStrategy":"validation","validationCode":"// guard: never drop+re-add a counter column name\nColumnMetadata dropped = table.getDroppedColumn(ByteBufferUtil.bytes(colName));\nif (table.isCounter() && dropped != null && newType.isCounter())\n    throw new IllegalArgumentException(\"Cannot re-add dropped counter column \" + colName + \"; use a new name.\");","typeGuard":"boolean counterReAddAllowed(TableMetadata t, String name) {\n    return !(t.isCounter() && t.getDroppedColumn(UTF8Type.instance.decompose(name)) != null);\n}","tryCatchPattern":"try {\n    session.execute(\"ALTER TABLE t ADD \" + colName + \" counter\");\n} catch (InvalidQueryException e) {\n    if (e.getMessage().contains(\"previously dropped counter column\"))\n        throw new SchemaConflictException(\"Counter columns cannot be re-added after drop (CASSANDRA-7831); use a new column name\", e);\n    throw e;\n}","preventionTips":["Never model counter resets as drop+add; use UPDATE t SET c = c - <value> instead.","Use fresh column names for each counter lifecycle (hits_2024, hits_2025).","Check system.dropped_columns before adding counter columns to a counter table.","Understand that dropped counter history is permanent — plan counter names up front."],"tags":["cql","schema","counter","alter-table","dropped-column"],"backgroundTag":"schema-validation-failed","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}