oracle/graal · error · IllegalArgumentException
Expected {} arguments, got {}
Error message
Expected {} arguments, got {} What it means
Thrown by EspressoExternalResolvedJavaMethod.invoke when the number of varargs JavaConstant arguments does not equal the method's parameter count (getSignature().getParameterCount(false), i.e. without the receiver). The adapter marshals arguments positionally into an Object[] for the guest interop execute, so an arity mismatch would shift every argument; it rejects early instead. Note the count excludes the receiver, so for instance methods callers must not include the receiver in arguments.
Source
Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaMethod.java:296
}
/// 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;
} else if (!isStatic()) {
if (!(receiver instanceof EspressoExternalObjectConstant objectConstant)) {
throw new IllegalArgumentException("Bad receiver: expected Object, got " + arguments[0].getJavaKind());
}
args[0] = objectConstant.getValue();
outputArgumentOffset = 1;
}
for (int i = 0; i < parameterCount; i++) {
JavaConstant argument = arguments[i];
JavaKind argumentKind = argument.getJavaKind();View on GitHub (pinned to a66e9ccd1d)
Solutions
- Build the argument array from method.getSignature().getParameterCount(false) and never include the receiver
- For guest varargs methods, assemble the trailing Object[] array yourself before invoking
- Re-resolve the ResolvedJavaMethod when the guest class changes instead of caching across redefinitions
Example fix
// before: reflect-style call with receiver in args method.invoke(receiver, allArgsWithReceiver); // after JavaConstant[] params = Arrays.copyOfRange(allArgsWithReceiver, 1, allArgsWithReceiver.length); method.invoke(receiver, params);
Defensive patterns
Strategy: validation
Validate before calling
int expected = method.getSignature().getParameterCount(false);
if (expected != args.length) {
throw new IllegalStateException(method.getName() + ": expected " + expected + " args, got " + args.length);
} Prevention
- Never include the receiver in the arguments array; it is a separate parameter
- Assemble guest varargs arrays yourself — the adapter does not pack trailing arguments
- Re-resolve methods when guest classes change instead of caching (method, argCount) pairs
When it happens
Trigger: Passing the receiver inside arguments for an instance method (off-by-one), omitting varargs (the adapter does not assemble Object... arrays automatically), or calling with constants from a stale signature after the guest class was recompiled with a different parameter list.
Common situations: Adapting java.lang.reflect.Method.invoke (whose args[0] is the receiver) to this API; snapshot/replay of invocations across guest class versions; generic dispatch tables that cache (method, argTemplate) pairs.
Related errors
- For static methods or constructors, the receiver argument mu
- For instance methods, the receiver argument must not be null
- For instance methods, the receiver argument must not represe
- Bad receiver: expected Object, got {}
- Bad argument kind at index {}: expected Boolean, got {}
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/93642788437787c4.
Report an issue: GitHub.