apache/iceberg · error · UnsupportedOperationException
Cannot update statistics of a %s table
Error message
Cannot update statistics of a %s table
What it means
Statistics updates (write table statistics files) are mutation operations that BaseReadOnlyTable does not support. updateStatistics() always throws UnsupportedOperationException for a read-only table descriptor.
Source
Thrown at core/src/main/java/org/apache/iceberg/BaseReadOnlyTable.java:99
public RowDelta newRowDelta() {
throw new UnsupportedOperationException(
"Cannot remove or replace rows in a " + descriptor + " table");
}
@Override
public ReplacePartitions newReplacePartitions() {
throw new UnsupportedOperationException(
"Cannot replace partitions in a " + descriptor + " table");
}
@Override
public DeleteFiles newDelete() {
throw new UnsupportedOperationException("Cannot delete from a " + descriptor + " table");
}
@Override
public UpdateStatistics updateStatistics() {
throw new UnsupportedOperationException(
"Cannot update statistics of a " + descriptor + " table");
}
@Override
public UpdatePartitionStatistics updatePartitionStatistics() {
throw new UnsupportedOperationException(
"Cannot update partition statistics of a " + descriptor + " table");
}
@Override
public ExpireSnapshots expireSnapshots() {
throw new UnsupportedOperationException(
"Cannot expire snapshots from a " + descriptor + " table");
}
@Override
public ManageSnapshots manageSnapshots() {
throw new UnsupportedOperationException(View on GitHub (pinned to 86d9c8fc54)
Solutions
- Use catalog.loadTable() to obtain a writable table handle before updating statistics.
- Skip statistics publication for read-only descriptors by checking the descriptor first.
- Publish statistics through a transaction on the real table.
Example fix
// before readOnlyTable.updateStatistics().setStatisticsCommit(snapshotId, statsFile).commit(); // after Table table = catalog.loadTable(tableIdentifier); table.updateStatistics().setStatisticsCommit(snapshotId, statsFile).commit();
Defensive patterns
Strategy: validation
Validate before calling
if (!(table instanceof BaseReadOnlyTable)) {
table.updateStatistics().setStatisticsCommit(snapshotId, statsFile).commit();
} Type guard
boolean supportsStatsUpdate(Table t) { return !(t instanceof BaseReadOnlyTable); } Try / catch
try { table.updateStatistics()...commit(); } catch (UnsupportedOperationException e) { LOG.warn("Skipping stats update on read-only table"); } Prevention
- Publish statistics only from jobs that own a writable table handle
- Skip read-only descriptors in stats-publishing pipelines
When it happens
Trigger: Calling table.updateStatistics() on a read-only table instance, e.g. when a statistics-publishing job is handed a snapshot wrapper instead of the live table.
Common situations: Compute engines publishing statistics files after analysis jobs; automation that assumes every Table handle is writable.
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
- %s doesn't implement copyWithStats
- Updating statistics is not supported by + getClass().getName
- Updating statistics is not supported by + getClass().getName
- this.getClass().getName() + " does not implement computeTabl
- Cannot update the schema of a %s table
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/b9766907e336e82d.
Report an issue: GitHub.