oracle/graal · error · IllegalArgumentException

For static methods or constructor, the receiver argument…

Error message

For static methods or constructor, the receiver argument must be null

What it means

Thrown by HostVMAccess.invoke when invoking a static method or a constructor with a non-null receiver JavaConstant. Reflection semantics require no receiver for static/constructor execution, so this is an API-contract violation by the caller, not a runtime failure of the target code.

Solutions

  1. Pass null as receiver when the executable is static or a constructor
  2. Branch on Modifier.isStatic(executable.getModifiers()) / instanceof Constructor before building the call, mirroring the guard in HostVMAccess
  3. If you expected an instance method, verify the ResolvedJavaMethod really resolves to a non-static original via SnippetReflectionProvider.originalMethod

Example fix

// before
hostVM.invoke(staticMethod, snippetReflection.forObject(obj), args);  // throws

// after
Object receiverConst = Modifier.isStatic(executable.getModifiers()) || executable instanceof Constructor
        ? null
        : snippetReflection.forObject(obj);
hostVM.invoke(staticMethod, receiverConst, args);
Defensive patterns

Strategy: validation

Validate before calling

Executable ex = snippetReflection.originalMethod(method);
boolean noReceiver = Modifier.isStatic(ex.getModifiers()) || ex instanceof Constructor;
if (noReceiver && receiver != null) throw new IllegalArgumentException("receiver must be null");

Type guard

static boolean takesReceiver(Executable ex) { return !Modifier.isStatic(ex.getModifiers()) && !(ex instanceof Constructor); }

Try / catch

catch (IllegalArgumentException e) { fail fast with the executable identity in the message }

Prevention

When it happens

Trigger: Calling invoke(method, receiver, args...) where method maps to a static Executable or a Constructor and receiver is any non-null JavaConstant (even JavaConstant.NULL_POINTER counts as non-null here).

Common situations: Generic invocation code that always forwards a receiver constant (e.g. a snippet host or a test harness that reuses one call path for instance and static methods), or misclassifying a method as instance because Modifier.isStatic was checked on the wrong mirror after snippet substitution.

Related errors


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

Appendix: source

Thrown at compiler/src/jdk.graal.compiler.hostvmaccess/src/jdk/graal/compiler/hostvmaccess/HostVMAccess.java:142

    public boolean owns(ResolvedJavaMethod value) {
        return value.getClass().getModule() == hostImplModule;
    }

    @Override
    public boolean owns(ResolvedJavaField value) {
        return value.getClass().getModule() == hostImplModule;
    }

    @Override
    public JavaConstant invoke(ResolvedJavaMethod method, JavaConstant receiver, JavaConstant... arguments) {
        SnippetReflectionProvider snippetReflection = providers.getSnippetReflection();
        Executable executable = snippetReflection.originalMethod(method);
        makeAccessible(executable);
        boolean isConstructor = executable instanceof Constructor;
        Class<?>[] parameterTypes = executable.getParameterTypes();
        if (Modifier.isStatic(executable.getModifiers()) || isConstructor) {
            if (receiver != null) {
                throw new IllegalArgumentException("For static methods or constructor, 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");
        }
        if (parameterTypes.length != arguments.length) {
            throw new IllegalArgumentException("Wrong number of arguments: expected " + parameterTypes.length + " but got " + arguments.length);
        }
        Signature signature = method.getSignature();
        Object[] unboxedArguments = new Object[parameterTypes.length];
        for (int i = 0; i < unboxedArguments.length; i++) {
            JavaKind parameterKind = signature.getParameterKind(i);
            JavaConstant argument = arguments[i];
            if (parameterKind.isObject()) {
                if (argument.isNull()) {
                    unboxedArguments[i] = null;
                } else {

View on GitHub (pinned to a66e9ccd1d)