apache/iceberg · error · java.lang.IllegalArgumentException
Cannot use catalog ( ): not a TableCatalog
Error message
Cannot use catalog %s(%s): not a TableCatalog
What it means
asTableCatalog requires that the resolved Spark CatalogPlugin implements the TableCatalog interface. Catalogs that only support views, functions, or session state cannot host Iceberg tables, so this IllegalArgumentException reports the catalog name and class that failed the check.
Solutions
- Point the operation at a catalog that implements TableCatalog (e.g. an Iceberg catalog registered via spark.sql.catalog.<name>).
- Set spark.sql.defaultCatalog to a table-capable catalog.
- Check the class name in the message — it tells you which CatalogPlugin was resolved and whether that's what you intended.
- Register the Iceberg catalog explicitly and qualify the table name with it: my_catalog.db.table.
Example fix
// before
spark.conf.set("spark.sql.defaultCatalog", "spark_catalog");
CREATE TABLE t (...) USING iceberg; // throws
// after
spark.conf.set("spark.sql.defaultCatalog", "iceberg_catalog");
CREATE TABLE t (...) USING iceberg; // ok Defensive patterns
Strategy: type-guard
Validate before calling
// Java/Scala check before DDL
CatalogPlugin cat = lookupCatalog(catalogName);
if (!(cat instanceof TableCatalog)) {
throw new IllegalStateException("Catalog " + catalogName + " cannot host tables");
} Type guard
boolean isTableCatalog(CatalogPlugin catalog) {
return catalog instanceof TableCatalog;
} Try / catch
try {
SparkCatalog ops = (SparkCatalog) catalog;
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("not a TableCatalog")) {
// route to a different catalog or surface a config hint
}
} Prevention
- Set spark.sql.defaultCatalog to a TableCatalog implementation
- Always qualify table names with your Iceberg catalog name (my_catalog.db.table)
- Verify catalog registrations in spark.sql.catalog.* before running DDL
- Check the class name in the error to confirm which catalog was actually resolved
When it happens
Trigger: Referencing a table in a catalog that does not implement TableCatalog — e.g. pointing USE/CREATE TABLE at spark_catalog, a view catalog, or a function catalog via Spark3Util.catalogAndIdentifier/asTableCatalog paths.
Common situations: Configuring spark.sql.defaultCatalog to a non-table catalog; writing CREATE TABLE ... USING iceberg with the table name resolving to a legacy session catalog; typos in catalog names that fall back to spark_catalog.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Cannot use catalog ( ): not a TableCatalog
- 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
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/3a17673548f92961.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:862
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)