apache/iceberg · error · IllegalArgumentException

Cannot initialize LockManager, missing no-arg constructor: %

Error message

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

What it means

LockManagers.loadLockManager builds the configured LockManager implementation via DynConstructors expecting a no-arg constructor. If the class exists but has none, it throws IllegalArgumentException naming the implementation class.

Source

Thrown at core/src/main/java/org/apache/iceberg/util/LockManagers.java:62

  public static LockManager defaultLockManager() {
    return LOCK_MANAGER_DEFAULT;
  }

  public static LockManager from(Map<String, String> properties) {
    if (properties.containsKey(CatalogProperties.LOCK_IMPL)) {
      return loadLockManager(properties.get(CatalogProperties.LOCK_IMPL), properties);
    } else {
      return defaultLockManager();
    }
  }

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

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

    lockManager.initialize(properties);
    return lockManager;
  }

  public abstract static class BaseLockManager implements LockManager {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Add a public no-arg constructor to the LockManager implementation and move logic into initialize(Map<String,String>)
  2. Verify lock.impl points to the correct, fully-qualified concrete class
  3. Fall back to the default in-memory lock manager for single-JVM use

Example fix

// before
class MyLockManager implements LockManager {
  MyLockManager(String path) { ... }
}
// after
class MyLockManager implements LockManager {
  public MyLockManager() { }
  @Override
  public void initialize(Map<String, String> properties) { this.path = properties.get("path"); }
}
Defensive patterns

Strategy: try-catch

Validate before calling

Class<?> c = Class.forName(impl);
if (!LockManager.class.isAssignableFrom(c)) throw new IllegalArgumentException(impl + " is not a LockManager");
if (c.getDeclaredConstructor() == null || !java.lang.reflect.Modifier.isPublic(c.getDeclaredConstructor().getModifiers())) throw new IllegalArgumentException(impl + " needs a public no-arg constructor");

Try / catch

try { LockManagers.from(properties); } catch (IllegalArgumentException e) { /* fall back to default lock manager */ }

Prevention

When it happens

Trigger: Setting lock.impl to a LockManager class that only defines parameterized constructors (custom lock managers typically require a no-arg ctor because initialize(properties) is called separately).

Common situations: Custom LockManager implementations that put initialization logic in a constructor with arguments; inner classes without a public no-arg constructor; copying an example class whose constructor signature was changed.

Related errors


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