apache/iceberg · error · UnsupportedOperationException
Cannot call refresh on temporary table operations
Error message
Cannot call refresh on temporary table operations
What it means
TemporaryTableOperations (the anonymous subclass returned for uncommitted transaction metadata) cannot reload state from a metastore because it only holds in-memory, uncommitted metadata. Its refresh() override therefore throws UnsupportedOperationException to make clear that refresh semantics do not apply to temporary operations.
Source
Thrown at core/src/main/java/org/apache/iceberg/BaseMetastoreTableOperations.java:248
return metadataFileLocation(current(), filename);
}
@Override
public LocationProvider locationProvider() {
return LocationProviders.locationsFor(current().location(), current().properties());
}
@Override
public TableOperations temp(TableMetadata uncommittedMetadata) {
return new TableOperations() {
@Override
public TableMetadata current() {
return uncommittedMetadata;
}
@Override
public TableMetadata refresh() {
throw new UnsupportedOperationException(
"Cannot call refresh on temporary table operations");
}
@Override
public void commit(TableMetadata base, TableMetadata metadata) {
throw new UnsupportedOperationException("Cannot call commit on temporary table operations");
}
@Override
public String metadataFileLocation(String fileName) {
return BaseMetastoreTableOperations.this.metadataFileLocation(
uncommittedMetadata, fileName);
}
@Override
public LocationProvider locationProvider() {
return LocationProviders.locationsFor(
uncommittedMetadata.location(), uncommittedMetadata.properties());View on GitHub (pinned to 86d9c8fc54)
Solutions
- Do not call refresh on temporary table operations; read uncommittedMetadata via current() instead
- Commit the staged transaction through the real catalog first, then operate on the resulting table's operations
- Restructure code to distinguish TableOperations from temporary/staged operations before refreshing
Example fix
// before tempOps.refresh(); // UnsupportedOperationException TableMetadata meta = tempOps.current(); // after TableMetadata meta = tempOps.current(); // temporary ops already expose in-memory metadata // refresh only on real, metastore-backed TableOperations
Defensive patterns
Strategy: type-guard
Validate before calling
if (isTemporaryOps(ops)) { readFromCurrentMetadata(ops); } else { ops.refresh(); } Type guard
boolean isTemporaryOps(TableOperations ops) { return ops instanceof BaseMetastoreTableOperations temp && !supportsRealRefresh; /* or track a flag when constructing temporary ops */ } Try / catch
try { ops.refresh(); }
catch (UnsupportedOperationException e) { /* temporary ops: use current() metadata instead */ } Prevention
- Track whether operations are temporary/staged and branch before refreshing
- Read staged state via current() only
- Commit staged work through the catalog before refreshing
When it happens
Trigger: Calling refresh() on TableOperations obtained from a temporary/staged table (e.g., transaction staging APIs or uncommitted metadata snapshots); any code path that calls current() triggering an internal refresh request on temporary ops.
Common situations: Staged/branch-like transaction workflows (stageCreate-like usage) where code treats the temporary ops like normal table ops; utility code that unconditionally refreshes before reading; tests that mix real and temporary operations.
Related errors
- Updating statistics is not supported by + getClass().getName
- Updating partition statistics is not supported by + getClass
- Managing snapshots is not supported by + getClass().getName(
- Cannot call commit on temporary table operations
- Cannot create transactions for a %s table
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9287663ca5da3a0b.
Report an issue: GitHub.