apache/iceberg · error · UnsupportedOperationException

Cannot create transactions for a %s table

Error message

Cannot create transactions for a %s table

What it means

Read-only table guard in BaseReadOnlyTable: newTransaction() would open a multi-operation transaction against the table, which read-only table wrappers do not permit. It fires on the call itself; the 'descriptor' in the message identifies which kind of read-only view rejected it.

Source

Thrown at core/src/main/java/org/apache/iceberg/BaseReadOnlyTable.java:123

    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)

Solutions

  1. Obtain a writable table handle with catalog.loadTable(identifier) before newTransaction().
  2. Restrict read-only handles to scan/plan code paths.
  3. Add an instanceof/capability check in shared write utilities.

Example fix

// before
Transaction tx = readOnlyTable.newTransaction();
// after
Table table = catalog.loadTable(tableIdentifier);
Transaction tx = table.newTransaction();
Defensive patterns

Strategy: validation

Validate before calling

if (!(table instanceof BaseReadOnlyTable)) {
  Transaction tx = table.newTransaction();
}

Type guard

boolean supportsTransactions(Table t) { return !(t instanceof BaseReadOnlyTable); }

Try / catch

try { Transaction tx = table.newTransaction(); } catch (UnsupportedOperationException e) { table = catalog.loadTable(ident); }

Prevention

When it happens

Trigger: Calling table.newTransaction() on any BaseReadOnlyTable-backed instance (snapshot wrapper, metadata table).

Common situations: Generic ETL code starting a transaction against whichever Table object it was handed, including snapshot handles used for time-travel reads.

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/a215b1f74e473998. Report an issue: GitHub.