apache/iceberg · error · IllegalArgumentException

Cannot initialize S3FileIOAwsClientFactory, missing no-arg c

Error message

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

What it means

S3FileIOAwsClientFactories.loadClientFactory instantiates the configured custom S3FileIOAwsClientFactory implementation via DynConstructors, which looks up a no-arg constructor (possibly non-public). If the implementation lacks one, NoSuchMethodException is wrapped as this IllegalArgumentException, because factories must be instantiable without arguments before initialize(Map) is called.

Source

Thrown at aws/src/main/java/org/apache/iceberg/aws/S3FileIOAwsClientFactories.java:60

    String factoryImpl =
        PropertyUtil.propertyAsString(properties, S3FileIOProperties.CLIENT_FACTORY, null);
    if (Strings.isNullOrEmpty(factoryImpl)) {
      return (T) AwsClientFactories.from(properties);
    }
    return (T) loadClientFactory(factoryImpl, properties);
  }

  private static S3FileIOAwsClientFactory loadClientFactory(
      String impl, Map<String, String> properties) {
    DynConstructors.Ctor<S3FileIOAwsClientFactory> ctor;
    try {
      ctor =
          DynConstructors.builder(S3FileIOAwsClientFactory.class)
              .loader(S3FileIOAwsClientFactories.class.getClassLoader())
              .hiddenImpl(impl)
              .buildChecked();
    } catch (NoSuchMethodException e) {
      throw new IllegalArgumentException(
          String.format(
              "Cannot initialize S3FileIOAwsClientFactory, missing no-arg constructor: %s", impl),
          e);
    }

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

    factory.initialize(properties);
    return factory;

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Add a public (or at least accessible) no-arg constructor to the factory class.
  2. Move configuration handling from the constructor into initialize(Map<String, String>).
  3. Verify the configured implementation class name points to your factory, not another type.

Example fix

// before
public class MyFactory implements S3FileIOAwsClientFactory {
  public MyFactory(Map<String, String> props) { ... }
}
// after
public class MyFactory implements S3FileIOAwsClientFactory {
  public MyFactory() {}
  public void initialize(Map<String, String> props) { ... }
}
Defensive patterns

Strategy: type-guard

Validate before calling

Class<?> c = Class.forName(factoryClassName);
boolean ok = java.util.Arrays.stream(c.getConstructors()).anyMatch(ctor -> ctor.getParameterCount() == 0);
if (!ok) throw new IllegalStateException(factoryClassName + " needs a no-arg constructor");

Type guard

static boolean hasNoArgCtor(Class<?> c) {
  try { c.getDeclaredConstructor(); return true; } catch (NoSuchMethodException e) { return false; }
}

Try / catch

try {
  S3FileIO io = new S3FileIO(config); // loads custom factory
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("missing no-arg constructor")) {
    LOG.error("Custom S3 client factory {} must have a no-arg constructor", config.get("io.impl"));
  }
  throw e;
}

Prevention

When it happens

Trigger: Setting s3.io-impl / the S3FileIO client factory implementation property (io.impl or similar consumed by initialize) to a class without a no-arg constructor; the class exists so Class loading succeeds but constructor lookup fails.

Common situations: Implementing a custom factory that takes configuration via constructor instead of initialize(Map); using a singleton-style class with a private constructor taking arguments; refactoring that added constructor parameters.

Related errors


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