{"record":{"id":"3a17673548f92961","repo":"apache/iceberg","slug":"cannot-use-catalog-s-s-not-a-tablecatalog-3a1767","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/v4.2/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java","lineNumber":862,"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":844,"sourceCodeEnd":880,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java#L844-L880","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nspark.conf.set(\"spark.sql.defaultCatalog\", \"spark_catalog\");\nCREATE TABLE t (...) USING iceberg; // throws\n// after\nspark.conf.set(\"spark.sql.defaultCatalog\", \"iceberg_catalog\");\nCREATE TABLE t (...) USING iceberg; // ok","handlingStrategy":"type-guard","validationCode":"// Java/Scala check before DDL\nCatalogPlugin cat = lookupCatalog(catalogName);\nif (!(cat instanceof TableCatalog)) {\n  throw new IllegalStateException(\"Catalog \" + catalogName + \" cannot host tables\");\n}","typeGuard":"boolean isTableCatalog(CatalogPlugin catalog) {\n  return catalog instanceof TableCatalog;\n}","tryCatchPattern":"try {\n  SparkCatalog ops = (SparkCatalog) catalog;\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"not a TableCatalog\")) {\n    // route to a different catalog or surface a config hint\n  }\n}","preventionTips":["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"],"tags":["spark","catalog","type-mismatch","tablecatalog"],"backgroundTag":"incompatible-source-type","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"}