apache/iceberg · error · UnsupportedOperationException

does not support creating tables

Error message

 does not support creating tables

What it means

This UnsupportedOperationException is a deliberate guard in SparkCachedTableCatalog.createTable: the catalog only serves cached views of already-existing Iceberg tables, so it has no write path to register a new table. Any Spark call that resolves CREATE TABLE (or REPLACE/CREATE OR REPLACE) against this catalog — e.g. a CREATE TABLE USING iceberg statement routed here instead of SparkCatalog — hits this sentinel and fails immediately, before any IO occurs.

Source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkCachedTableCatalog.java:98

    SparkTable table = load(ident);
    Preconditions.checkArgument(
        table.snapshotId() == null, "Cannot time travel based on both table identifier and AS OF");
    // Spark passes microseconds but Iceberg uses milliseconds for snapshots
    long timestampMillis = TimeUnit.MICROSECONDS.toMillis(timestampMicros);
    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

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Create tables in the real Iceberg catalog (SparkCatalog), not the cached-table catalog
  2. Set spark.sql.defaultCatalog to the persistent Iceberg catalog for DDL
  3. Cache the created table via SparkTableCache first if you need it served by this catalog

Example fix

// before
spark.sql("CREATE TABLE cached_catalog.db.t ...")
// after
spark.conf.set("spark.sql.defaultCatalog", "iceberg_real");
spark.sql("CREATE TABLE iceberg_real.db.t ...")
Defensive patterns

Strategy: validation

Validate before calling

if (catalog instanceof SparkCachedTableCatalog) {
  throw new IllegalArgumentException("Use the persistent Iceberg catalog to create tables");
}

Try / catch

try { catalog.createTable(ident, schema, partitions, props); } catch (UnsupportedOperationException e) { realCatalog.createTable(ident, schema, partitions, props); }

Prevention

When it happens

Trigger: Running CREATE TABLE ... USING iceberg with the cached catalog as the target catalog, invoking Catalog#createTable via Spark's TableCatalog API.

Common situations: Misconfigured default/session catalog pointing at SparkCachedTableCatalog; user attempts DDL in SQL expecting a persistent catalog.

Related errors


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