{"record":{"id":"9b84fea5dc0166ab","repo":"apache/iceberg","slug":"cannot-use-catalog-s-s-not-a-tablecatalog-9b84fe","errorCode":null,"errorMessage":"Cannot use catalog %s(%s): not a TableCatalog","messagePattern":"Cannot use catalog (.+?)\\((.+?)\\): not a TableCatalog","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java","lineNumber":832,"sourceCode":"              try {\n                return catalogManager.catalog(catalogName);\n              } catch (Exception e) {\n                LOG.warn(\"Failed to load catalog: {}\", catalogName, e);\n                return null;\n              }\n            },\n            Identifier::of,\n            defaultCatalog,\n            currentNamespace);\n    return new CatalogAndIdentifier(catalogIdentifier);\n  }\n\n  private static TableCatalog asTableCatalog(CatalogPlugin catalog) {\n    if (catalog instanceof TableCatalog) {\n      return (TableCatalog) catalog;\n    }\n\n    throw new IllegalArgumentException(\n        String.format(\n            \"Cannot use catalog %s(%s): not a TableCatalog\",\n            catalog.name(), catalog.getClass().getName()));\n  }\n\n  /** This mimics a class inside of Spark which is private inside of LookupCatalog. */\n  public static class CatalogAndIdentifier {\n    private final CatalogPlugin catalog;\n    private final Identifier identifier;\n\n    public CatalogAndIdentifier(CatalogPlugin catalog, Identifier identifier) {\n      this.catalog = catalog;\n      this.identifier = identifier;\n    }\n\n    public CatalogAndIdentifier(Pair<CatalogPlugin, Identifier> identifier) {\n      this.catalog = identifier.first();\n      this.identifier = identifier.second();","sourceCodeStart":814,"sourceCodeEnd":850,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java#L814-L850","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nspark.conf: spark.sql.catalog.spark_catalog=org.apache.spark.sql.internal.CatalogImpl\n// after\nspark.conf: spark.sql.catalog.spark_catalog=org.apache.iceberg.spark.SparkSessionCatalog","handlingStrategy":"type-guard","validationCode":"if (!(catalog instanceof org.apache.spark.sql.connector.catalog.TableCatalog)) {\n  throw new IllegalArgumentException(\"Catalog \" + catalog.name() + \" does not support tables\");\n}","typeGuard":"java.util.Optional<TableCatalog> asTableCatalogSafe(CatalogPlugin c) {\n  return (c instanceof TableCatalog tc) ? java.util.Optional.of(tc) : java.util.Optional.empty();\n}","tryCatchPattern":"try {\n  TableCatalog tc = Spark3Util.catalogAndIdentifier(spark, name).catalog();\n} catch (IllegalArgumentException e) {\n  throw new IllegalStateException(\"Configure the target catalog as a TableCatalog (Iceberg catalog or SparkSessionCatalog)\", e);\n}","preventionTips":["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"],"tags":["spark","catalog","type-cast"],"backgroundTag":"invalid-argument-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}