apache/iceberg · error · UnsupportedOperationException
Cannot modify a static table
Error message
Cannot modify a static table
What it means
StaticTableOperations.commit throws UnsupportedOperationException because a static table is a read-only view over a fixed TableMetadata (typically used to read time-travel snapshots or Hadoop-provided metadata files without a catalog). Committing changes to a static table is intentionally impossible — mutations must go through a real catalog-backed Table.
Source
Thrown at core/src/main/java/org/apache/iceberg/StaticTableOperations.java:80
staticMetadata = TableMetadataParser.read(io, metadataFileLocation);
}
return staticMetadata;
}
/**
* StaticTableOperations works on the same version of TableMetadata, and it will never refer a
* different TableMetadata object than the one it was created with.
*
* @return always {@link #current()}.
*/
@Override
public TableMetadata refresh() {
return current();
}
@Override
public void commit(TableMetadata base, TableMetadata metadata) {
throw new UnsupportedOperationException("Cannot modify a static table");
}
@Override
public FileIO io() {
return this.io;
}
@Override
public String metadataFileLocation(String fileName) {
throw new UnsupportedOperationException("Cannot modify a static table");
}
@Override
public LocationProvider locationProvider() {
return locationProvider;
}
}
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Load a catalog-backed table instead of a static one, then perform writes through it (catalog.loadTable(identifier) and use the returned Table for mutations).
- If you need time travel plus writes, use table.timeMachine-style snapshot selection (Spark: VERSION AS OF) on the catalog table rather than a static table handle.
- For metadata changes, operate on the source catalog: e.g. HiveCatalog/RESTCatalog loadTable -> update operations -> commit.
- Restructure code to treat statically-loaded tables as read-only and route writes to a separate writable handle.
Example fix
// before
Table table = new BaseTable(
new StaticTableOperations(metadataFileLocation, fileIO), "static");
table.updateSchema().addColumn("new_col", Types.StringType.get()).commit(); // throws
// after
Catalog catalog = ...; // e.g. HiveCatalog / RESTCatalog
Table table = catalog.loadTable(TableIdentifier.of("db", "tbl"));
table.updateSchema().addColumn("new_col", Types.StringType.get()).commit(); Defensive patterns
Strategy: try-catch
Validate before calling
// Java: detect static tables before writing
if (((HasTableOperations) table).operations() instanceof StaticTableOperations) {
throw new IllegalStateException("Load via a Catalog to write this table");
} Type guard
// Java
boolean isWritable(Table table) {
return !(((HasTableOperations) table).operations() instanceof StaticTableOperations);
} Try / catch
// Java
try {
table.updateSchema().addColumn("c", Types.StringType.get()).commit();
} catch (UnsupportedOperationException e) {
if (e.getMessage().contains("static table")) {
Table live = catalog.loadTable(tableIdentifier);
live.updateSchema().addColumn("c", Types.StringType.get()).commit();
} else { throw e; }
} Prevention
- Only use static tables for read-only inspection or time-travel reads.
- Always load tables from a Catalog when the workflow includes writes or DDL.
- Document/review code paths that construct BaseTable with StaticTableOperations.
When it happens
Trigger: Calling any write/DDL operation on a static table — table.updateSchema().commit(), appendFiles(table).commit(), refreshAndCreateTransaction, updateLocation, etc. — where the Table was built from StaticTableOperations (e.g. via new StaticTableOperations(metadataFile, io) or time-travel/static readers).
Common situations: Loading a table with Table.load static helpers or time-travel snapshots and then attempting appends/schema updates; scripts that migrate from Hive tables loaded statically; assuming every Table handle is writable because the Table interface exposes write APIs.
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
- Operation updateSchema is not supported after the table is s
- Operation updateSpec is not supported after the table is ser
- Operation updateProperties is not supported after the table
- Operation replaceSortOrder is not supported after the table
- Setting values is not supported
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/4622527a207d1263.
Report an issue: GitHub.