apache/iceberg · error · UnsupportedOperationException
Cannot expire snapshots from a
Error message
Cannot expire snapshots from a %s table
What it means
Read-only table guard in BaseReadOnlyTable: expireSnapshots() mutates table state, which is not allowed on this read-only view of a table (e.g. a materialized/branch view described by 'descriptor'). Any call fails before touching metadata — the table handle, not the snapshots, is the limiting factor.
Solutions
- Call expireSnapshots() on the live table loaded via catalog.loadTable().
- Perform expiration inside a transaction on the writable table.
- In generic cleanup code, resolve the parent table handle before expiring.
Example fix
// before readOnlyTable.expireSnapshots().expireOlderThan(ts).commit(); // after Table table = catalog.loadTable(tableIdentifier); table.expireSnapshots().expireOlderThan(ts).commit();
Defensive patterns
Strategy: validation
Validate before calling
if (!(table instanceof BaseReadOnlyTable)) {
table.expireSnapshots().expireOlderThan(cutoff).commit();
} Type guard
boolean supportsExpiration(Table t) { return !(t instanceof BaseReadOnlyTable); } Try / catch
try { table.expireSnapshots()...commit(); } catch (UnsupportedOperationException e) { /* expire via the parent table instead */ } Prevention
- Run expiration jobs against catalog-loaded tables only
- Never iterate snapshot objects calling expireSnapshots on each
When it happens
Trigger: Calling table.expireSnapshots() on a snapshot wrapper or any BaseReadOnlyTable-backed descriptor.
Common situations: Retention/cleanup jobs iterating snapshots and attempting expiration directly on the snapshot object instead of the parent table.
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
- Cannot append to a table
- Cannot create transactions for a
- Cannot delete from a
- Cannot manage snapshots in a
- Cannot overwrite in a
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/5a82917df0056f10.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/BaseReadOnlyTable.java:111
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(
"Cannot manage snapshots in a " + descriptor + " table");
}
@Override
public Transaction newTransaction() {
throw new UnsupportedOperationException(
"Cannot create transactions for a " + descriptor + " table");
}
}
View on GitHub (pinned to 86d9c8fc54)