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

  1. Do not call refresh on temporary operations; finish the transaction commit first, then reload the table via catalog.loadTable(...) which has real operations.
  2. Restructure code so metadata reads during a transaction use the in-memory current() metadata instead of refresh.
  3. Catch UnsupportedOperationException around mid-transaction refresh calls if the code path is shared.
  4. 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

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/92e16c2efaa52ae2. Report an issue: GitHub.