apache/iceberg · error · java.lang.UnsupportedOperationException

SparkCachedTableCatalog does not support altering tables

Error message

SparkCachedTableCatalog does not support altering tables

What it means

SparkCachedTableCatalog is a read-only catalog that serves Iceberg tables from an in-process cache (e.g. for cached table scans in Spark). It intentionally implements the Spark CatalogPlugin DDL surface but rejects every mutation. alterTable() throws UnsupportedOperationException because cached tables are snapshots of existing tables and must be altered through the real catalog that owns them.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkCachedTableCatalog.java:103

    long snapshotId = SnapshotUtil.snapshotIdAsOfTime(table.table(), timestampMillis);
    return table.copyWithSnapshotId(snapshotId);
  }

  @Override
  public void invalidateTable(Identifier ident) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support table invalidation");
  }

  @Override
  public SparkTable createTable(
      Identifier ident, StructType schema, Transform[] partitions, Map<String, String> properties)
      throws TableAlreadyExistsException {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support creating tables");
  }

  @Override
  public SparkTable alterTable(Identifier ident, TableChange... changes) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support altering tables");
  }

  @Override
  public boolean dropTable(Identifier ident) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support dropping tables");
  }

  @Override
  public boolean purgeTable(Identifier ident) throws UnsupportedOperationException {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support purging tables");
  }

  @Override
  public void renameTable(Identifier oldIdent, Identifier newIdent) {
    throw new UnsupportedOperationException(CLASS_NAME + " does not support renaming tables");
  }

  @Override

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Resolve the table through the real catalog (SparkCatalog / HiveCatalog / HadoopCatalog) and apply the TableChange there.
  2. Use ALTER TABLE on the original unqualified or properly catalog-qualified identifier so Spark does not route to SparkCachedTableCatalog.
  3. If you own the code path, hold the underlying org.apache.iceberg.Table and use table.updateSchema()/updateProperties() instead of the catalog DDL API.

Example fix

// before
SparkCachedTableCatalog catalog = ...;
catalog.alterTable(Identifier.of(new String[]{"db"}, "t"), TableChange.addColumn("c", Types.IntegerType.get()));

// after
SparkCatalog realCatalog = ...; // catalog that actually owns the table
realCatalog.alterTable(Identifier.of(new String[]{"db"}, "t"), TableChange.addColumn("c", Types.IntegerType.get()));
Defensive patterns

Strategy: validation

Validate before calling

if (catalog instanceof SparkCachedTableCatalog || catalog.name().contains("CachedTable")) {
  throw new IllegalArgumentException("DDL not supported on cached table catalog; use the owning catalog");
}

Type guard

boolean supportsDdl = !(catalog instanceof SparkCachedTableCatalog);

Prevention

When it happens

Trigger: Calling SparkCachedTableCatalog.alterTable(ident, changes...) directly, or running Spark SQL DDL (ALTER TABLE ... / DESCRIBE-driven ALTER) whose catalog resolution lands on the cached-table catalog (identifiers like 'spark_catalog.<cached-namespace>.<table>').

Common situations: Pasting an ALTER TABLE statement into a session where the table was loaded through the cached catalog; programmatically applying TableChange objects against the cache-backed catalog; framework code that generically applies schema evolution to whatever catalog the identifier resolves to.

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