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

  1. Branch on method.isStatic() || method.isConstructor() and pass null as the receiver in those cases
  2. For constructors, pass only the declared parameters — the adapter allocates the instance itself
  3. 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

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


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/2f12053b8f2310e8. Report an issue: GitHub.