apache/iceberg · error · IllegalArgumentException
Cannot use catalog ( ): not a TableCatalog
Error message
Cannot use catalog %s(%s): not a TableCatalog
What it means
Spark3Util.asTableCatalog narrows a Spark CatalogPlugin to org.apache.spark.sql.connector.catalog.TableCatalog. If the resolved catalog does not implement TableCatalog (e.g. it is a V1SessionCatalog or another non-table catalog type), it throws IllegalArgumentException 'Cannot use catalog %s(%s): not a TableCatalog'.
Solutions
- Register the target catalog as a TableCatalog (e.g. set spark.sql.catalog.<name> to an Iceberg catalog implementation)
- If the intent is the session catalog, replace spark_catalog with org.apache.iceberg.spark.SparkSessionCatalog in the config
- Check the resolved catalog name/class in the error message and correct the identifier's first part
Example fix
// before spark.conf: spark.sql.catalog.spark_catalog=org.apache.spark.sql.internal.CatalogImpl // after spark.conf: spark.sql.catalog.spark_catalog=org.apache.iceberg.spark.SparkSessionCatalog
Defensive patterns
Strategy: type-guard
Validate before calling
if (!(catalog instanceof org.apache.spark.sql.connector.catalog.TableCatalog)) {
throw new IllegalArgumentException("Catalog " + catalog.name() + " does not support tables");
} Type guard
java.util.Optional<TableCatalog> asTableCatalogSafe(CatalogPlugin c) {
return (c instanceof TableCatalog tc) ? java.util.Optional.of(tc) : java.util.Optional.empty();
} Try / catch
try {
TableCatalog tc = Spark3Util.catalogAndIdentifier(spark, name).catalog();
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Configure the target catalog as a TableCatalog (Iceberg catalog or SparkSessionCatalog)", e);
} Prevention
- Register catalogs with spark.sql.catalog.<name> set to a TableCatalog implementation
- Use SparkSessionCatalog for the spark_catalog when Iceberg manages session tables
- Verify the first identifier part names a table-capable catalog, not a function/view catalog
When it happens
Trigger: Resolving an identifier whose first part maps to a catalog that only implements CatalogPlugin/FunctionCatalog (e.g. the legacy session catalog 'spark_catalog' configured as a V1 adapter) through helpers like catalogAndIdentifier/tableCatalog lookups.
Common situations: Pointing Iceberg at the session catalog without an Iceberg-based spark_catalog replacement; typos in catalog name resolving to a non-table catalog; using catalogs registered for views/functions only.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot use non-v1 table
- Altering a view is not supported by catalog:
- Altering a view is not supported by catalog
- Altering a view is not supported by catalog
- Altering a view is not supported by catalog
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9b84fea5dc0166ab.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:832
try {
return catalogManager.catalog(catalogName);
} catch (Exception e) {
LOG.warn("Failed to load catalog: {}", catalogName, e);
return null;
}
},
Identifier::of,
defaultCatalog,
currentNamespace);
return new CatalogAndIdentifier(catalogIdentifier);
}
private static TableCatalog asTableCatalog(CatalogPlugin catalog) {
if (catalog instanceof TableCatalog) {
return (TableCatalog) catalog;
}
throw new IllegalArgumentException(
String.format(
"Cannot use catalog %s(%s): not a TableCatalog",
catalog.name(), catalog.getClass().getName()));
}
/** This mimics a class inside of Spark which is private inside of LookupCatalog. */
public static class CatalogAndIdentifier {
private final CatalogPlugin catalog;
private final Identifier identifier;
public CatalogAndIdentifier(CatalogPlugin catalog, Identifier identifier) {
this.catalog = catalog;
this.identifier = identifier;
}
public CatalogAndIdentifier(Pair<CatalogPlugin, Identifier> identifier) {
this.catalog = identifier.first();
this.identifier = identifier.second();View on GitHub (pinned to 86d9c8fc54)