apache/iceberg · error · IllegalArgumentException

Cannot initialize Catalog, %s does not implement Catalog.

Error message

Cannot initialize Catalog, %s does not implement Catalog.

What it means

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.

Source

Thrown at core/src/main/java/org/apache/iceberg/CatalogUtil.java:289

   */
  public static Catalog loadCatalog(
      String impl, String catalogName, Map<String, String> properties, Object hadoopConf) {
    Preconditions.checkNotNull(impl, "Cannot initialize custom Catalog, impl class name is null");
    DynConstructors.Ctor<Catalog> ctor;
    try {
      ctor = DynConstructors.builder(Catalog.class).impl(impl).buildChecked();
    } catch (NoSuchMethodException e) {
      throw new IllegalArgumentException(
          String.format("Cannot initialize Catalog implementation %s: %s", impl, e.getMessage()),
          e);
    }

    Catalog catalog;
    try {
      catalog = ctor.newInstance();

    } catch (ClassCastException e) {
      throw new IllegalArgumentException(
          String.format("Cannot initialize Catalog, %s does not implement Catalog.", impl), e);
    }

    configureHadoopConf(catalog, hadoopConf);

    catalog.initialize(catalogName, properties);
    return catalog;
  }

  /**
   * Build an Iceberg {@link Catalog} based on a map of catalog properties and optional Hadoop
   * configuration.
   *
   * <p>This method examines both the {@link #ICEBERG_CATALOG_TYPE} and {@link
   * CatalogProperties#CATALOG_IMPL} properties to determine the catalog implementation to load. If
   * nothing is specified for both properties, Hive catalog will be loaded by default.
   *
   * @param name catalog name

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Set catalog-impl (or loadCatalog's impl argument) to a class that actually implements org.apache.iceberg.Catalog.
  2. 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.
  3. Deduplicate the classpath so only one Iceberg version/bundle is present, avoiding split Catalog interfaces across classloaders.
  4. If it is a custom catalog, make it implement org.apache.iceberg.Catalog and rebuild against the same Iceberg version in use.

Example fix

// before
conf.set("io.catalog-impl", "org.apache.iceberg.aws.s3.S3FileIO"); // FileIO, not a Catalog
// after
conf.set("io.catalog-impl", "org.apache.iceberg.aws.s3.S3FileIO");
conf.set("catalog-impl", "org.apache.iceberg.rest.RESTCatalog"); // a real Catalog impl
Defensive patterns

Strategy: validation

Validate before calling

Class<?> cls = Class.forName(implClassName);
if (!Catalog.class.isAssignableFrom(cls)) {
  throw new IllegalArgumentException(implClassName + " does not implement org.apache.iceberg.Catalog");
}

Type guard

static boolean implementsIcebergCatalog(String impl) {
  try {
    return Catalog.class.isAssignableFrom(Class.forName(impl));
  } catch (Throwable t) {
    return false;
  }
}

Try / catch

try {
  Catalog catalog = CatalogUtil.loadCatalog(impl, name, props, conf);
} catch (IllegalArgumentException e) {
  if (e.getCause() instanceof ClassCastException) {
    throw new ConfigException("catalog-impl %s is not a Catalog implementation", impl, e);
  }
  throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/e3f27b3d93ce18d1. Report an issue: GitHub.