oracle/graal · error · IllegalArgumentException
For static methods or constructors, the receiver argument mu
Error message
For static methods or constructors, the receiver argument must be null
What it means
Thrown by EspressoExternalResolvedJavaMethod.invoke when invoking a static method or constructor with a non-null receiver. Constructors get their receiver (the allocated instance) from unsafeAllocateInstance internally, and static methods have no receiver at all, so any receiver constant supplied by the caller makes the argument-to-Value marshalling ambiguous and is rejected up front. This is a usage-contract guard on the private invoke adapter used by the external vmaccess layer to call into the guest Espresso VM.
Source
Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaMethod.java:286
protected boolean equals0(AbstractEspressoResolvedJavaMethod that) {
if (that instanceof EspressoExternalResolvedJavaMethod espressoMethod) {
return this.vmMethodMirror.equals(espressoMethod.vmMethodMirror);
}
return false;
}
@Override
protected int hashCode0() {
return vmMethodMirror.hashCode();
}
/// Adapts a call to a guest Espresso method, converting between [JavaConstant] values and
/// the polyglot [Value]s, and back. The interop implementation in the Espresso is
/// `com.oracle.truffle.espresso.impl.Method.Execute#invoke`.
JavaConstant invoke(JavaConstant receiver, JavaConstant... arguments) {
if (isStatic() || isConstructor()) {
if (receiver != null) {
throw new IllegalArgumentException("For static methods or constructors, the receiver argument must be null");
}
} else if (receiver == null) {
throw new NullPointerException("For instance methods, the receiver argument must not be null");
} else if (receiver.isNull()) {
throw new IllegalArgumentException("For instance methods, the receiver argument must not represent a null constant");
}
AbstractEspressoSignature signature = getSignature();
int parameterCount = signature.getParameterCount(false);
if (parameterCount != arguments.length) {
throw new IllegalArgumentException("Expected " + parameterCount + " arguments, got " + arguments.length);
}
Object[] args = new Object[arguments.length + (isConstructor() || !isStatic() ? 1 : 0)];
int outputArgumentOffset = 0;
EspressoExternalVMAccess access = getAccess();
if (isConstructor()) {
EspressoExternalResolvedInstanceType type = (EspressoExternalResolvedInstanceType) getDeclaringClass();
args[0] = access.unsafeAllocateInstance(type).getValue();
outputArgumentOffset = 1;View on GitHub (pinned to a66e9ccd1d)
Solutions
- Branch on method.isStatic() || method.isConstructor() and pass null as the receiver in those cases
- For constructors, pass only the declared parameters — the adapter allocates the instance itself
- Wrap call sites in a helper that normalizes (receiver, args) according to the method modifiers
Example fix
// before
JavaConstant result = method.invoke(receiverMaybeNonNull, args);
// after
JavaConstant result = method.invoke(
method.isStatic() || method.isConstructor() ? null : receiverMaybeNonNull,
args); Defensive patterns
Strategy: validation
Validate before calling
boolean noReceiver = method.isStatic() || method.isConstructor();
if (noReceiver && receiver != null) throw new IllegalStateException("drop receiver for " + method.getName());
JavaConstant r = noReceiver ? null : requireNonNull(receiver); Prevention
- Route all calls through one helper that normalizes receiver nullability from method.isStatic()/isConstructor()
- Constructors: the adapter allocates the instance itself — pass only declared parameters
- When a method changes from instance to static, update call sites, not just the resolution
When it happens
Trigger: Calling invoke(methodIsStatic, receiver, args...) with a receiver constant because the call site handles static and instance methods uniformly; adapting ResolvedJavaMethod.invokeStatic/invokeWithArguments generically without branching on isStatic()/isConstructor().
Common situations: Generic reflection-style bridges (snippets, substitution frameworks, JVMTI-like tooling) that pass the receiver through for all methods; refactors that changed a method from instance to static while callers kept passing 'this'.
Related errors
- For instance methods, the receiver argument must not represe
- Bad receiver: expected Object, got {}
- For instance methods, the receiver argument must not be null
- Expected {} arguments, got {}
- Bad argument kind at index {}: expected Boolean, got {}
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/2f12053b8f2310e8.
Report an issue: GitHub.