apache/cassandra · error · InvalidRequestException
Cannot add a column '%s' of type %s, incompatible with previ
Error message
Cannot add a column '%s' of type %s, incompatible with previously dropped column '%s' of type %s
What it means
After a column is dropped, Cassandra remembers its type so it can deserialize any lingering data. Re-adding a column of the same name with a type that is not serialization-compatible with the dropped type is rejected (CASSANDRA-8099), because reading old sstables could produce corrupted or misinterpreted values, especially under schema races.
Source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java:386
// check for nested non-frozen UDTs or collections in a non-frozen UDT
if (type.isUDT() && type.isMultiCell())
{
for (AbstractType<?> fieldType : ((UserType) type).fieldTypes())
{
if (fieldType.isMultiCell())
throw ire("Non-frozen UDTs with nested non-frozen collections are not supported for column " + column.name);
}
}
ColumnMetadata droppedColumn = table.getDroppedColumn(name.bytes);
if (null != droppedColumn)
{
// After #8099, not safe to re-add columns of incompatible types - until *maybe* deser logic with dropped
// columns is pushed deeper down the line. The latter would still be problematic in cases of schema races.
if (!type.isSerializationCompatibleWith(droppedColumn.type))
{
throw ire("Cannot add a column '%s' of type %s, incompatible with previously dropped column '%s' of type %s",
name,
type.asCQL3Type(),
name,
droppedColumn.type.asCQL3Type());
}
if (droppedColumn.isStatic() != isStatic)
{
throw ire("Cannot re-add previously dropped column '%s' of kind %s, incompatible with previous kind %s",
name,
isStatic ? ColumnMetadata.Kind.STATIC : ColumnMetadata.Kind.REGULAR,
droppedColumn.kind);
}
// Cannot re-add a dropped counter column. See #7831.
if (table.isCounter())
throw ire("Cannot re-add previously dropped counter column %s", name);
}View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Use a new column name instead of reusing the dropped one, e.g. ALTER TABLE t ADD col2 <type>.
- Re-add the column with exactly the same type (or a serialization-compatible one) as when it was dropped.
- Check the dropped column's recorded type via system_schema.columns / sstable metadata (system.dropped_columns) to match it.
- If the old data is fully expired (GC grace passed) and the table history cleared, recreate the table to purge the dropped-column record, then add the column with the new type.
Example fix
// before ALTER TABLE t DROP cnt; ALTER TABLE t ADD cnt text; -- fails: was int // after ALTER TABLE t DROP cnt; ALTER TABLE t ADD cnt_text text; -- new name -- or: ALTER TABLE t ADD cnt int; -- same, compatible type
Defensive patterns
Strategy: validation
Validate before calling
// before re-adding a dropped column name
ColumnMetadata dropped = table.getDroppedColumn(ByteBufferUtil.bytes(colName));
if (dropped != null && !newType.isSerializationCompatibleWith(dropped.type))
throw new IllegalArgumentException("Type " + newType.asCQL3Type() + " incompatible with dropped column of " + dropped.type.asCQL3Type()); Type guard
boolean canReAdd(TableMetadata t, String name, AbstractType<?> type) {
ColumnMetadata d = t.getDroppedColumn(UTF8Type.instance.decompose(name));
return d == null || type.isSerializationCompatibleWith(d.type);
} Try / catch
try {
session.execute(alterAdd);
} catch (InvalidQueryException e) {
if (e.getMessage().contains("incompatible with previously dropped column"))
throw new SchemaConflictException("Choose a new column name or the original type", e);
throw e;
} Prevention
- Never reuse dropped column names for different types; prefer new names (col_v2).
- Query system.dropped_columns / system_schema history to check a name's dropped type before re-adding.
- Treat DROP COLUMN as permanent from the application's naming perspective.
- Keep schema migrations idempotent by generating unique column names per type change.
When it happens
Trigger: ALTER TABLE t DROP col; then ALTER TABLE t ADD col <different_type> where the new type fails AbstractType.isSerializationCompatibleWith(dropped type) — e.g. int dropped, text re-added; or same name with an incompatible non-frozen/frozen collection change.
Common situations: Reusing a dropped column name with a different type; schema-sync tools renaming/re-typing a column by drop+add; migrating after a type change decision; accidental reuse of a name from long ago that is still in the dropped-columns history.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Cannot re-add previously dropped column '%s' of kind %s, inc
- Cannot re-add previously dropped counter column %s
- Static columns are only useful (and thus allowed) if the tab
- Cannot %s column %s because it has dependent secondary index
- Column %s was not found in table '%s'
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/5c0f634443ed9055.
Report an issue: GitHub.