apache/iceberg · error · IllegalArgumentException

Cannot initialize TLSConfigurer

Error message

Cannot initialize TLSConfigurer, %s does not implement TLSConfigurer.

What it means

HTTPClient instantiates the configured TLS implementation reflectively; if ctor.newInstance() returns an object that is not a TLSConfigurer, the ClassCastException is converted into an IllegalArgumentException with this message. The configured class exists and is constructible but does not implement the required interface.

Solutions

  1. Make the configured class implement TLSConfigurer (and keep the public no-arg constructor).
  2. Set the config property to a genuine TLSConfigurer implementation class.
  3. Check the package of the interface your class implements — a similarly named interface from another library does not count.
  4. Upgrade/downgrade so client and implementation agree on the TLSConfigurer interface version.

Example fix

// before: wrong interface
class MyTls extends CustomSslFactory {}
// after
public class MyTls implements org.apache.iceberg.rest.auth.TLSConfigurer {
  public MyTls() {}
  public void initialize(Map<String, String> properties) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = Class.forName(implClassName);
if (!TLSConfigurer.class.isAssignableFrom(c)) {
  throw new IllegalArgumentException(implClassName + " does not implement TLSConfigurer");
}

Try / catch

try {
  buildClient();
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("does not implement TLSConfigurer")) {
    // correct the configured class or fall back to the default TLS configurer
  }
  throw e;
}

Prevention

When it happens

Trigger: Setting the TLS implementation config property to a class that exists and has a no-arg constructor but does not implement org.apache.iceberg.rest.auth.TLSConfigurer — e.g. a random SSLContext factory or a class from a different library.

Common situations: Copying config from another framework (e.g. pointing at a generic SSLSocketFactory class); refactoring renamed/moved the interface so the class no longer implements TLSConfigurer; wrong class picked from an autocomplete list.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/rest/HTTPClient.java:462

    DynConstructors.Ctor<TLSConfigurer> ctor;
    try {
      ctor =
          DynConstructors.builder(TLSConfigurer.class)
              .loader(HTTPClient.class.getClassLoader())
              .impl(impl)
              .buildChecked();
    } catch (NoSuchMethodException e) {
      throw new IllegalArgumentException(
          String.format(
              "Cannot initialize TLSConfigurer implementation %s: %s", impl, e.getMessage()),
          e);
    }

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

    configurer.initialize(properties);

    return configurer;
  }

  @VisibleForTesting
  static ConnectionConfig configureConnectionConfig(Map<String, String> properties) {
    Long connectionTimeoutMillis =
        PropertyUtil.propertyAsNullableLong(properties, REST_CONNECTION_TIMEOUT_MS);
    Integer socketTimeoutMillis =
        PropertyUtil.propertyAsNullableInt(properties, REST_SOCKET_TIMEOUT_MS);

    if (connectionTimeoutMillis == null && socketTimeoutMillis == null) {

View on GitHub (pinned to 86d9c8fc54)