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");
}
@OverrideView on GitHub (pinned to 86d9c8fc54)
Solutions
- Create tables in the real Iceberg catalog (SparkCatalog), not the cached-table catalog
- Set spark.sql.defaultCatalog to the persistent Iceberg catalog for DDL
- 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
- Set spark.sql.defaultCatalog to a persistent catalog for DDL
- Never target the cached catalog in CREATE TABLE statements
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
- SparkCachedTableCatalog does not support altering tables
- SparkCachedTableCatalog does not support dropping tables
- SparkCachedTableCatalog does not support purging tables
- SparkCachedTableCatalog does not support renaming tables
- does not support altering tables
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/352ed9198ddac46d.
Report an issue: GitHub.