apache/iceberg · error · IllegalArgumentException

Cannot initialize MetricsReporter, missing no-arg…

Error message

Cannot initialize MetricsReporter, missing no-arg constructor: %s

What it means

CatalogUtil.loadMetricsReporter instantiates a MetricsReporter implementation reflectively via DynConstructors requiring a public no-arg constructor. If no such constructor exists, an IllegalArgumentException is thrown saying the reporter is missing a no-arg constructor. Metrics reporters must be instantiable without arguments because they are configured entirely through the initialize(Map) call with table properties.

Solutions

  1. Add a public no-arg constructor to the MetricsReporter implementation.
  2. Move constructor dependencies into the initialize(Map<String, String> properties) method, reading them from catalog/table properties.
  3. Point the metrics-impl property at a different class that has a public no-arg constructor.
  4. Verify the constructor is public and takes zero parameters (not inherited or narrowed visibility).

Example fix

// before
public class MyReporter implements MetricsReporter {
  private final String registry;
  public MyReporter(String registry) { this.registry = registry; }
}

// after
public class MyReporter implements MetricsReporter {
  private String registry;
  public MyReporter() {}
  @Override
  public void initialize(Map<String, String> properties) {
    this.registry = properties.get("metrics.registry");
  }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> reporterClass = Class.forName(metricsImplClass, false, CatalogUtil.class.getClassLoader());
java.lang.reflect.Constructor<?> noArg =
    java.util.Arrays.stream(reporterClass.getConstructors())
        .filter(c -> c.getParameterCount() == 0)
        .findFirst()
        .orElseThrow(() -> new IllegalStateException(
            metricsImplClass + " has no public no-arg constructor"));

Type guard

boolean hasNoArgConstructor(String className) {
  try {
    Class<?> c = Class.forName(className, false, Thread.currentThread().getContextClassLoader());
    return java.util.Arrays.stream(c.getConstructors())
        .anyMatch(k -> k.getParameterCount() == 0);
  } catch (ClassNotFoundException e) { return false; }
}

Try / catch

try {
  MetricsReporter r = CatalogUtil.loadMetricsReporter(impl, properties);
} catch (IllegalArgumentException e) {
  // fall back to default LoggingMetricsReporter and surface the bad config
  MetricsReporter r = new LoggingMetricsReporter();
  r.initialize(properties);
}

Prevention

When it happens

Trigger: Setting the metrics-impl property (or metrics-reporter-impl on a table) to a class that only defines parameterized constructors, e.g. new MyReporter(Factory) with no public MyReporter().

Common situations: Writing a custom reporter that takes constructor dependencies instead of configuring via initialize(); a reporter designed for programmatic use being wired in via config; constructor declared package-private or private instead of public.

Related errors


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

Appendix: source

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

   * @throws IllegalArgumentException if class path not found or right constructor not found or the
   *     loaded class cannot be cast to the given interface type
   */
  public static MetricsReporter loadMetricsReporter(Map<String, String> properties) {
    String impl = properties.get(CatalogProperties.METRICS_REPORTER_IMPL);
    if (impl == null) {
      return LoggingMetricsReporter.instance();
    }

    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;
  }

View on GitHub (pinned to 86d9c8fc54)