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

  1. Register the target catalog as a TableCatalog (e.g. set spark.sql.catalog.<name> to an Iceberg catalog implementation)
  2. If the intent is the session catalog, replace spark_catalog with org.apache.iceberg.spark.SparkSessionCatalog in the config
  3. 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

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


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)