apache/iceberg · error · UnsupportedOperationException
Cannot call refresh on temporary table operations
Error message
Cannot call refresh on temporary table operations
What it means
An UnsupportedOperationException thrown by the temporary TableOperations wrapper created during commit flows (an in-flight/uncommitted metadata holder). Its refresh() is intentionally unimplemented because the temporary operations have no backing table to re-read metadata from; calling refresh on it is a caller logic error.
Source
Thrown at core/src/main/java/org/apache/iceberg/rest/RESTTableOperations.java:343
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 RESTTableOperations.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 operations; finish the transaction commit first, then reload the table via catalog.loadTable(...) which has real operations.
- Restructure code so metadata reads during a transaction use the in-memory current() metadata instead of refresh.
- Catch UnsupportedOperationException around mid-transaction refresh calls if the code path is shared.
- Use the Table from catalog.loadTable after commit for any subsequent refresh-dependent logic.
Example fix
// before table.operations().refresh(); // table here is the temp in-transaction ops // after Table committed = catalog.loadTable(ident); committed.refresh();
Defensive patterns
Strategy: type-guard
Type guard
boolean supportsRefresh(TableOperations ops) { try { ops.refresh(); return true; } catch (UnsupportedOperationException e) { return false; } } // prefer: only call refresh on ops from catalog.loadTable Try / catch
try { ops.refresh(); } catch (UnsupportedOperationException e) { /* temporary in-transaction operations; use current() or reload table */ } Prevention
- Never call operations().refresh() during an open create/replace transaction
- Use current() for in-flight metadata reads
- Reload via catalog.loadTable(identifier) after commit for refresh semantics
- Avoid generic frameworks that blindly refresh operations on any Table reference
When it happens
Trigger: Calling table.operations().refresh() (or code paths that internally refresh) on the temporary TableOperations returned while a create/replace transaction is in progress via RESTTableOperations' temp operations object.
Common situations: Custom transaction or write code that touches operations().refresh() mid-transaction; frameworks that opportunistically refresh metadata between commits; debugging code calling refresh on the in-flight table.
Related errors
- Cannot call commit on temporary table operations
- 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 refresh on temporary table operations
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/92e16c2efaa52ae2.
Report an issue: GitHub.