apache/iceberg · error · java.lang.UnsupportedOperationException

SparkCachedTableCatalog does not support creating tables

Error message

SparkCachedTableCatalog does not support creating tables

What it means

Capability guard in SparkCachedTableCatalog.createTable: this catalog only serves loads of already-existing (cached) tables and cannot create them. Any CREATE attempt routed here fails; route the operation to the underlying Iceberg catalog instead.

Source

Thrown at spark/v3.5/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 catalog (spark_catalog / Iceberg catalog) rather than the cached-table catalog
  2. Ensure identifier resolution doesn't route DDL to SparkCachedTableCatalog
  3. If you need a persistent reference to cached data, create a temp view instead of a table

Example fix

// before
spark.sql("CREATE TABLE spark_catalog_cached.db.tbl (id BIGINT)"); // throws
// after
spark.sql("CREATE TABLE my_catalog.db.tbl (id BIGINT) USING iceberg");
Defensive patterns

Strategy: validation

Validate before calling

if (catalog instanceof SparkCachedTableCatalog) throw new IllegalStateException("DDL not allowed on cached-table catalog");

Try / catch

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

Prevention

When it happens

Trigger: Executing CREATE TABLE (or CREATE OR REPLACE TABLE) against the cached-table catalog, or API calls to createTable(ident, schema, partitions, properties) on this catalog.

Common situations: Queries that reference the cached catalog name by mistake in DDL; framework code attempting to materialize results into every available catalog.

Related errors


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