apache/iceberg · error · IllegalArgumentException

Cannot initialize MetricsReporter, %s does not implement Met

Error message

Cannot initialize MetricsReporter, %s does not implement MetricsReporter.

What it means

CatalogUtil.loadMetricsReporter instantiates the configured class and relies on the DynConstructors-built factory's generic cast to detect type errors. If the instantiated object does not actually implement MetricsReporter, newInstance() throws ClassCastException, which is converted to an IllegalArgumentException stating the class does not implement MetricsReporter. This guards the property-configured reporter type at load time.

Source

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

    LOG.info("Loading custom MetricsReporter implementation: {}", impl);
    DynConstructors.Ctor<MetricsReporter> ctor;
    try {
      ctor =
          DynConstructors.builder(MetricsReporter.class)
              .loader(CatalogUtil.class.getClassLoader())
              .impl(impl)
              .buildChecked();
    } catch (NoSuchMethodException e) {
      throw new IllegalArgumentException(
          String.format("Cannot initialize MetricsReporter, missing no-arg constructor: %s", impl),
          e);
    }

    MetricsReporter reporter;
    try {
      reporter = ctor.newInstance();
    } catch (ClassCastException e) {
      throw new IllegalArgumentException(
          String.format(
              "Cannot initialize MetricsReporter, %s does not implement MetricsReporter.", impl),
          e);
    }

    reporter.initialize(properties);

    return reporter;
  }

  public static String fullTableName(String catalogName, TableIdentifier identifier) {
    StringBuilder sb = new StringBuilder();

    if (catalogName.contains("/") || catalogName.contains(":")) {
      // use / for URI-like names: thrift://host:port/db.table
      sb.append(catalogName);
      if (!catalogName.endsWith("/")) {
        sb.append("/");

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Verify the configured class implements org.apache.iceberg.metrics.MetricsReporter and add `implements MetricsReporter` if missing.
  2. Check the metrics-impl property value for typos or copy-paste of the wrong fully qualified class name.
  3. Ensure a single, non-shaded copy of iceberg-core (and its MetricsReporter interface) is on the classpath so the instanceof check matches.
  4. Rebuild/redeploy the reporter class against the Iceberg version in use.

Example fix

// before
public class MyReporter implements io.micrometer.core.instrument.reporter.MetricsReporter { ... }

// after
import org.apache.iceberg.metrics.MetricsReporter;
public class MyReporter implements MetricsReporter {
  @Override public void initialize(Map<String, String> properties) { ... }
  @Override public void report(MetricsReport report) { ... }
}
Defensive patterns

Strategy: type-guard

Validate before calling

Class<?> reporterClass = Class.forName(metricsImplClass, false, CatalogUtil.class.getClassLoader());
if (!org.apache.iceberg.metrics.MetricsReporter.class.isAssignableFrom(reporterClass)) {
  throw new IllegalStateException(metricsImplClass + " does not implement MetricsReporter");
}

Type guard

boolean isMetricsReporter(String className, ClassLoader cl) {
  try {
    return org.apache.iceberg.metrics.MetricsReporter.class
        .isAssignableFrom(Class.forName(className, false, cl));
  } catch (ClassNotFoundException e) { return false; }
}

Try / catch

try {
  MetricsReporter r = CatalogUtil.loadMetricsReporter(impl, properties);
} catch (IllegalArgumentException e) {
  if (e.getCause() instanceof ClassCastException) {
    // wrong class configured for metrics-impl; verify with isAssignableFrom before retrying
  }
  throw e;
}

Prevention

When it happens

Trigger: Setting metrics-impl / metrics-reporter-impl to a class that is instantiable but does not implement org.apache.iceberg.metrics.MetricsReporter — e.g. a typo pointing to the wrong class or an unrelated class in the same package.

Common situations: Configured class implements a similarly named reporter interface from a different library or an older iceberg API; copy-paste of the impl string from another config; the class implements MetricsReporter from a shaded/duplicate copy of the iceberg API in a different classloader.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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