{"record":{"id":"e3f27b3d93ce18d1","repo":"apache/iceberg","slug":"cannot-initialize-catalog-s-does-not-implement-c","errorCode":null,"errorMessage":"Cannot initialize Catalog, %s does not implement Catalog.","messagePattern":"Cannot initialize Catalog, (.+?) does not implement Catalog\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/CatalogUtil.java","lineNumber":289,"sourceCode":"   */\n  public static Catalog loadCatalog(\n      String impl, String catalogName, Map<String, String> properties, Object hadoopConf) {\n    Preconditions.checkNotNull(impl, \"Cannot initialize custom Catalog, impl class name is null\");\n    DynConstructors.Ctor<Catalog> ctor;\n    try {\n      ctor = DynConstructors.builder(Catalog.class).impl(impl).buildChecked();\n    } catch (NoSuchMethodException e) {\n      throw new IllegalArgumentException(\n          String.format(\"Cannot initialize Catalog implementation %s: %s\", impl, e.getMessage()),\n          e);\n    }\n\n    Catalog catalog;\n    try {\n      catalog = ctor.newInstance();\n\n    } catch (ClassCastException e) {\n      throw new IllegalArgumentException(\n          String.format(\"Cannot initialize Catalog, %s does not implement Catalog.\", impl), e);\n    }\n\n    configureHadoopConf(catalog, hadoopConf);\n\n    catalog.initialize(catalogName, properties);\n    return catalog;\n  }\n\n  /**\n   * Build an Iceberg {@link Catalog} based on a map of catalog properties and optional Hadoop\n   * configuration.\n   *\n   * <p>This method examines both the {@link #ICEBERG_CATALOG_TYPE} and {@link\n   * CatalogProperties#CATALOG_IMPL} properties to determine the catalog implementation to load. If\n   * nothing is specified for both properties, Hive catalog will be loaded by default.\n   *\n   * @param name catalog name","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/CatalogUtil.java#L271-L307","documentation":"Thrown by CatalogUtil.loadCatalog after the class is instantiated reflectively but the resulting object cannot be cast to org.apache.iceberg.Catalog. DynConstructors bounds the constructor lookup to Catalog, so newInstance() yields a ClassCastException that is translated into this IllegalArgumentException, keeping the original cause.","triggerScenarios":"Passing a class name via loadCatalog / catalog-impl that exists on the classpath, has a no-arg constructor, but does not implement the org.apache.iceberg.Catalog interface (e.g. a FileIO class, a different project's Catalog type, or a relocated/shaded interface mismatch).","commonSituations":"Copy-pasting an implementation class name of the wrong kind (e.g. a FileIO impl like S3FileIO into catalog-impl); two Iceberg versions on the classpath so the class implements a different Catalog interface loaded by another classloader; custom catalog implementing a stale or relocated interface.","solutions":["Set catalog-impl (or loadCatalog's impl argument) to a class that actually implements org.apache.iceberg.Catalog.","Inspect the named class and confirm which interface it implements; if it is a FileIO, move it to the io-impl / FileIO config key instead.","Deduplicate the classpath so only one Iceberg version/bundle is present, avoiding split Catalog interfaces across classloaders.","If it is a custom catalog, make it implement org.apache.iceberg.Catalog and rebuild against the same Iceberg version in use."],"exampleFix":"// before\nconf.set(\"io.catalog-impl\", \"org.apache.iceberg.aws.s3.S3FileIO\"); // FileIO, not a Catalog\n// after\nconf.set(\"io.catalog-impl\", \"org.apache.iceberg.aws.s3.S3FileIO\");\nconf.set(\"catalog-impl\", \"org.apache.iceberg.rest.RESTCatalog\"); // a real Catalog impl","handlingStrategy":"validation","validationCode":"Class<?> cls = Class.forName(implClassName);\nif (!Catalog.class.isAssignableFrom(cls)) {\n  throw new IllegalArgumentException(implClassName + \" does not implement org.apache.iceberg.Catalog\");\n}","typeGuard":"static boolean implementsIcebergCatalog(String impl) {\n  try {\n    return Catalog.class.isAssignableFrom(Class.forName(impl));\n  } catch (Throwable t) {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  Catalog catalog = CatalogUtil.loadCatalog(impl, name, props, conf);\n} catch (IllegalArgumentException e) {\n  if (e.getCause() instanceof ClassCastException) {\n    throw new ConfigException(\"catalog-impl %s is not a Catalog implementation\", impl, e);\n  }\n  throw e;\n}","preventionTips":["Distinguish config keys: catalog-impl for Catalog classes, io-impl for FileIO classes.","Reference implementations from Iceberg docs (RESTCatalog, HiveCatalog, HadoopCatalog, JDBCcatalog, NessieCatalog, GlueCatalog, BigQueryCatalog).","Watch for mixed Iceberg versions causing interface identity mismatch.","Add an integration test that loads each configured catalog at deploy time."],"tags":["reflection","classcast","catalog","type-mismatch"],"backgroundTag":"type-mismatch","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"}