apache/iceberg · error · UnsupportedOperationException

Cannot modify a static table

Error message

Cannot modify a static table

What it means

StaticTableOperations.commit throws UnsupportedOperationException because a static table is a read-only view over a fixed TableMetadata (typically used to read time-travel snapshots or Hadoop-provided metadata files without a catalog). Committing changes to a static table is intentionally impossible — mutations must go through a real catalog-backed Table.

Source

Thrown at core/src/main/java/org/apache/iceberg/StaticTableOperations.java:80

      staticMetadata = TableMetadataParser.read(io, metadataFileLocation);
    }
    return staticMetadata;
  }

  /**
   * StaticTableOperations works on the same version of TableMetadata, and it will never refer a
   * different TableMetadata object than the one it was created with.
   *
   * @return always {@link #current()}.
   */
  @Override
  public TableMetadata refresh() {
    return current();
  }

  @Override
  public void commit(TableMetadata base, TableMetadata metadata) {
    throw new UnsupportedOperationException("Cannot modify a static table");
  }

  @Override
  public FileIO io() {
    return this.io;
  }

  @Override
  public String metadataFileLocation(String fileName) {
    throw new UnsupportedOperationException("Cannot modify a static table");
  }

  @Override
  public LocationProvider locationProvider() {
    return locationProvider;
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Load a catalog-backed table instead of a static one, then perform writes through it (catalog.loadTable(identifier) and use the returned Table for mutations).
  2. If you need time travel plus writes, use table.timeMachine-style snapshot selection (Spark: VERSION AS OF) on the catalog table rather than a static table handle.
  3. For metadata changes, operate on the source catalog: e.g. HiveCatalog/RESTCatalog loadTable -> update operations -> commit.
  4. Restructure code to treat statically-loaded tables as read-only and route writes to a separate writable handle.

Example fix

// before
Table table = new BaseTable(
    new StaticTableOperations(metadataFileLocation, fileIO), "static");
table.updateSchema().addColumn("new_col", Types.StringType.get()).commit(); // throws

// after
Catalog catalog = ...; // e.g. HiveCatalog / RESTCatalog
Table table = catalog.loadTable(TableIdentifier.of("db", "tbl"));
table.updateSchema().addColumn("new_col", Types.StringType.get()).commit();
Defensive patterns

Strategy: try-catch

Validate before calling

// Java: detect static tables before writing
if (((HasTableOperations) table).operations() instanceof StaticTableOperations) {
  throw new IllegalStateException("Load via a Catalog to write this table");
}

Type guard

// Java
boolean isWritable(Table table) {
  return !(((HasTableOperations) table).operations() instanceof StaticTableOperations);
}

Try / catch

// Java
try {
  table.updateSchema().addColumn("c", Types.StringType.get()).commit();
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("static table")) {
    Table live = catalog.loadTable(tableIdentifier);
    live.updateSchema().addColumn("c", Types.StringType.get()).commit();
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling any write/DDL operation on a static table — table.updateSchema().commit(), appendFiles(table).commit(), refreshAndCreateTransaction, updateLocation, etc. — where the Table was built from StaticTableOperations (e.g. via new StaticTableOperations(metadataFile, io) or time-travel/static readers).

Common situations: Loading a table with Table.load static helpers or time-travel snapshots and then attempting appends/schema updates; scripts that migrate from Hive tables loaded statically; assuming every Table handle is writable because the Table interface exposes write APIs.

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


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