{"record":{"id":"bd8145e6ebb88d6e","repo":"apache/iceberg","slug":"cannot-use-catalog-s-s-not-a-tablecatalog","errorCode":null,"errorMessage":"Cannot use catalog %s(%s): not a TableCatalog","messagePattern":"Cannot use catalog (.+?)\\((.+?)\\): not a TableCatalog","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java","lineNumber":827,"sourceCode":"            catalogName -> {\n              try {\n                return catalogManager.catalog(catalogName);\n              } catch (Exception 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":809,"sourceCodeEnd":845,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java#L809-L845","documentation":"asTableCatalog casts a Spark CatalogPlugin to TableCatalog and throws IllegalArgumentException when the catalog implementation does not support table operations (e.g. it is a function catalog or a generic catalog).","triggerScenarios":"Resolving a table identifier whose first part names a catalog that is not a TableCatalog — e.g. pointing Iceberg procedures/ALTER TABLE at a catalog registered as CatalogPlugin but not implementing TableCatalog.","commonSituations":"Misconfigured spark.sql.catalog.<name> entries where the class implements only CatalogPlugin; using session catalog defaults that resolve to a non-table catalog.","solutions":["Set spark.sql.catalog.<name> to a TableCatalog implementation (e.g. org.apache.iceberg.spark.SparkCatalog or SparkSessionCatalog)","Verify the catalog class with: spark.sessionState().catalogManager().catalog(name) instanceof TableCatalog before use","Use the correct catalog name in the identifier — the current name resolves to the wrong plugin"],"exampleFix":"// before\nspark.conf.set(\"spark.sql.catalog.my_cat\", \"org.apache.spark.sql.catalog.MyFuncCatalog\");\n// after\nspark.conf.set(\"spark.sql.catalog.my_cat\", \"org.apache.iceberg.spark.SparkCatalog\");","handlingStrategy":"type-guard","validationCode":"CatalogPlugin cat = catalogManager.catalog(name);\nif (!(cat instanceof TableCatalog)) { throw new IllegalStateException(name + \" is not a TableCatalog\"); }","typeGuard":"if (catalog instanceof TableCatalog) { /* safe to use */ }","tryCatchPattern":"try { return Spark3Util.catalogAndIdentifier(spark, ident); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"not a TableCatalog\")) { /* fix catalog config */ } throw e; }","preventionTips":["Register catalogs with org.apache.iceberg.spark.SparkCatalog or SparkSessionCatalog","Check catalog instanceof TableCatalog before DDL/identifier resolution","Avoid using function-only catalogs as default catalog for table operations"],"tags":["spark","catalog","configuration"],"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-14T16:17:12.679Z"}