oracle/graal · error · IllegalArgumentException

Wrong number of arguments: expected {} but got {}

Error message

Wrong number of arguments: expected {} but got {}

What it means

Thrown by HostVMAccess.invoke when the number of argument constants does not match the reflective parameter count of the target executable. The host VM unboxes arguments positionally, so arity must match exactly before any conversion is attempted.

Source

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

    @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 {
                    unboxedArguments[i] = snippetReflection.asObject(parameterTypes[i], argument);
                    if (unboxedArguments[i] == null) {
                        throw new IllegalArgumentException(
                                        "Illegal argument type: arguments[" + i + "] of type " + providers.getMetaAccess().lookupJavaType(arguments[i]).toClassName() +
                                                        " could not be converted to a " + parameterTypes[i]);
                    }
                }
            } else {

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Log both numbers from the exception and fix the argument array to match parameterTypes.length
  2. For instance methods make sure the receiver goes in the receiver parameter, not arguments[]
  3. For varargs targets, pass the trailing array as a single argument constant or expand it to match the declared arity
  4. Re-resolve the method after signature changes instead of caching old arity assumptions

Example fix

// before
hostVM.invoke(instanceMethod, null, arg0, arg1);          // receiver leaked into varargs
hostVM.invoke(twoArgMethod, receiver, onlyArg0);            // missing arg

// after
hostVM.invoke(instanceMethod, forObject(obj), arg0, arg1);
hostVM.invoke(twoArgMethod, receiver, arg0, arg1);
Defensive patterns

Strategy: validation

Validate before calling

if (executable.getParameterCount() != arguments.length) {
    throw new IllegalArgumentException("arity mismatch for " + executable);

Try / catch

catch (IllegalArgumentException e) { log expected vs got counts; regenerate the argument list }

Prevention

When it happens

Trigger: Calling invoke(method, receiver, args...) where args.length != executable.getParameterTypes().length — e.g. passing a receiver inside the varargs array for an instance method, forgetting a varargs spread, or dropping trailing arguments.

Common situations: Migrating call sites between APIs where the receiver is positional vs separate; handling signature-polymorphic or varargs methods whose reflective parameter count differs from source-level arity; stale hardcoded argument lists after a target method signature change.

Related errors


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