apache/cassandra · error · InvalidRequestException
Cannot add new column to a COMPACT STORAGE table
Error message
Cannot add new column to a COMPACT STORAGE table
What it means
Tables created WITH COMPACT STORAGE use the legacy Thrift-compatible storage format with a fixed column set; adding new columns via ALTER TABLE is rejected. Compact tables cannot gain new non-primary columns after creation.
Solutions
- Migrate the table to a regular (non-compact) schema: create a new table without COMPACT STORAGE and copy data across
- If the legacy schema must stay, add needed data via the existing sparse column encoding or a companion table
- Check table params: SELECT * FROM system_schema.tables WHERE keyspace_name=? AND table_name=? (compact_storage flag) before scripting DDL
Example fix
// before
session.execute("ALTER TABLE my_app.legacy_metrics ADD description text");
// after
session.execute("CREATE TABLE my_app.metrics (id uuid PRIMARY KEY, value blob, description text)");
// then copy data from legacy_metrics into metrics and drop the compact table Defensive patterns
Strategy: validation
Validate before calling
Row r = session.execute("SELECT * FROM system_schema.tables WHERE keyspace_name=? AND table_name=?", ks, table).one();
if (r != null && r.getBoolean("compact_storage"))
throw new IllegalStateException("Cannot ADD columns to a COMPACT STORAGE table"); Try / catch
try {
session.execute(alter);
} catch (InvalidRequestException e) {
if (e.getMessage().contains("COMPACT STORAGE"))
log.error("Legacy compact table requires migration before schema change");
else throw e;
} Prevention
- Detect COMPACT STORAGE tables during migration planning
- Plan full re-creation + data copy for extending legacy tables
- Avoid creating new tables WITH COMPACT STORAGE
When it happens
Trigger: ALTER TABLE ... ADD on a table where table.isCompactTable() is true — i.e. tables created with WITH COMPACT STORAGE, typically legacy tables migrated from Thrift
Common situations: Operating on legacy Thrift-era tables; applying generic schema migration scripts (written for regular tables) against compact-storage tables; attempting to extend an old data model in place.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- ACCESS TO DATACENTERS operations not supported by…
- Altering column types is no longer supported
- Cannot add a counter column to Accord table
- Cannot drop a table when materialized views still depend on…
- Cannot use ALTER TABLE on a materialized view; use ALTER…
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/026b33427cad48f9.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java:364
Views.Builder viewsBuilder)
{
ColumnIdentifier name = column.name;
AbstractType<?> type = column.type.prepare(keyspaceName, keyspace.types).getType();
boolean isStatic = column.isStatic;
ColumnMask mask = column.mask == null ? null : column.mask.prepare(keyspaceName, tableName, name, type, keyspace.userFunctions);
ColumnConstraints columnConstraints = column.constraints == null ? ColumnConstraints.NO_OP : column.constraints.prepare(name);
if (null != tableBuilder.getColumn(name)) {
if (!ifColumnNotExists)
throw ire("Column with name '%s' already exists", name);
return;
}
if (type.isCounter() && (table.params.transactionalMode.accordIsEnabled || table.params.transactionalMigrationFrom.migratingFromAccord()))
throw ire(format(ACCORD_COUNTER_COLUMN_UNSUPPORTED, keyspaceName, tableName, table.params.transactionalMode, table.params.transactionalMigrationFrom));
if (table.isCompactTable())
throw ire("Cannot add new column to a COMPACT STORAGE table");
if (isStatic && table.clusteringColumns().isEmpty())
throw ire("Static columns are only useful (and thus allowed) if the table has at least one clustering column");
// 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 droppedView on GitHub (pinned to 88fd0f6a0e)