apache/iceberg · error · IllegalStateException
Cannot bind constructors
Error message
Cannot bind constructors
What it means
A constructor handle produced by DynConstructors cannot be bound to a receiver instance — constructors are invoked with their arguments directly and are conceptually static. Calling bind(receiver) on such a handle throws this IllegalStateException by design.
Solutions
- Don't call bind() on constructor handles; invoke with newInstance(...) or newInstanceChecked(...) passing constructor arguments.
- Separate constructor lookups from method lookups so bind() is only called on genuine method handles.
- Check isStatic() before binding — constructor handles report isStatic() == true and cannot bind a receiver.
- If a receiver-ful call is intended, look up an instance method via DynMethods instead of DynConstructors.
Example fix
// before DynMethods.UnboundMethod ctor = DynConstructors.builder().impl(Foo.class).build(); Foo f = ctor.bind(receiver).invoke(); // after Foo f = DynConstructors.builder().impl(Foo.class).build().newInstance();
Defensive patterns
Strategy: type-guard
Validate before calling
DynMethods.UnboundMethod handle = /* looked up */;
if (handle.isStatic()) {
// constructor or static handle: never call bind(receiver)
} Type guard
boolean canBindReceiver(DynMethods.UnboundMethod m) { return !m.isStatic(); } Try / catch
try {
bound = handle.bind(receiver);
} catch (IllegalStateException e) {
if (e.getMessage().equals("Cannot bind constructors")) {
throw new IllegalStateException("Use newInstance(args) for constructor handles, not bind()", e);
}
throw e;
} Prevention
- Never call bind() on handles obtained from DynConstructors — use newInstance/newInstanceChecked
- Keep constructor and method reflection in separate code paths
- Gate bind() calls behind isStatic() checks
- Write a small unit test exercising the reflective invocation path before shipping
When it happens
Trigger: Treating a DynConstructors handle like a DynMethods handle: holding a CtorHandle (as a DynMethods.UnboundMethod) and calling bind(obj) to attach a receiver instead of calling newInstance(args).
Common situations: Generic reflective-dispatch code written against DynMethods that was handed a constructor handle; mixing constructor and method lookups in one code path.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot find constructor for
- Cannot initialize AwsClientFactory, missing no-arg…
- Cannot initialize DellClientFactory, missing no-arg…
- Cannot initialize MetricsReporter, missing no-arg…
- Cannot initialize S3FileIOAwsClientFactory, missing no-arg…
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/d78a2106b741965f.
Report an issue: GitHub.
Appendix: source
Thrown at common/src/main/java/org/apache/iceberg/common/DynConstructors.java:104
@Override
@SuppressWarnings("unchecked")
public <R> R invoke(Object target, Object... args) {
Preconditions.checkArgument(
target == null, "Invalid call to constructor: target must be null");
return (R) newInstance(args);
}
@Override
@SuppressWarnings("unchecked")
<R> R invokeChecked(Object target, Object... args) throws Exception {
Preconditions.checkArgument(
target == null, "Invalid call to constructor: target must be null");
return (R) newInstanceChecked(args);
}
@Override
public DynMethods.BoundMethod bind(Object receiver) {
throw new IllegalStateException("Cannot bind constructors");
}
@Override
public boolean isStatic() {
return true;
}
@Override
public String toString() {
return getClass().getSimpleName() + "(constructor=" + ctor + ", class=" + constructed + ")";
}
}
/**
* Constructs a new builder for finding a constructor dynamically.
*
* @return a Builder for finding a constructor
*/View on GitHub (pinned to 86d9c8fc54)