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 asserts that a resolved Spark CatalogPlugin actually implements Spark's TableCatalog interface. Catalogs that only provide views or are metadata-only (e.g. a catalog that is not a table catalog) cannot load/modify tables, so this throws IllegalArgumentException with the catalog's name and class.
Solutions
- Point the operation at a catalog configured with a TableCatalog implementation (e.g. org.apache.iceberg.spark.SparkCatalog)
- Check the catalog class with SHOW CATALOGS / spark.conf.get("spark.sql.catalog.<name>") and fix the configuration
- Use the correct catalog prefix in the table identifier instead of relying on delegation
Example fix
// before
spark.conf.set("spark.sql.catalog.local", "org.apache.spark.sql.catalog.SomeNonTableCatalog");
// after
spark.conf.set("spark.sql.catalog.local", "org.apache.iceberg.spark.SparkCatalog"); Defensive patterns
Strategy: validation
Validate before calling
CatalogPlugin c = ...; if (!(c instanceof TableCatalog)) { throw new IllegalArgumentException("Catalog " + c.name() + " does not support tables"); } Type guard
java.util.Optional<TableCatalog> asTableCatalog(CatalogPlugin c) { return (c instanceof TableCatalog) ? java.util.Optional.of((TableCatalog) c) : java.util.Optional.empty(); } Try / catch
try { return catalog.loadTable(ident); } catch (IllegalArgumentException e) { if (e.getMessage().contains("not a TableCatalog")) { throw new IllegalStateException("Configure spark.sql.catalog.<name> to a TableCatalog"); } throw e; } Prevention
- Verify every spark.sql.catalog.<name> config points to a TableCatalog implementation
- Fully qualify table names so operations don't fall through to a non-table catalog
- Add a startup check that resolves and asserts catalog types
When it happens
Trigger: Calling SparkCatalog/SparkSessionCatalog operations that funnel through asTableCatalog (loadTable, createTable, alterTable, etc.) when the resolved catalog is a CatalogPlugin but not a TableCatalog instance.
Common situations: Configuring spark.sql.catalog.<name> to a non-table catalog implementation and then addressing tables through it; delegating to the session catalog when it doesn't support tables; typos routing operations to the wrong catalog.
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 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/380cc02696d7ee26.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java:879
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)