{"record":{"id":"93642788437787c4","repo":"oracle/graal","slug":"expected-arguments-got","errorCode":null,"errorMessage":"Expected {} arguments, got {}","messagePattern":"Expected (.+?) arguments, got (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaMethod.java","lineNumber":296,"sourceCode":"    }\n\n    /// Adapts a call to a guest Espresso method, converting between [JavaConstant] values and\n    /// the polyglot [Value]s, and back. The interop implementation in the Espresso is\n    /// `com.oracle.truffle.espresso.impl.Method.Execute#invoke`.\n    JavaConstant invoke(JavaConstant receiver, JavaConstant... arguments) {\n        if (isStatic() || isConstructor()) {\n            if (receiver != null) {\n                throw new IllegalArgumentException(\"For static methods or constructors, the receiver argument must be null\");\n            }\n        } else if (receiver == null) {\n            throw new NullPointerException(\"For instance methods, the receiver argument must not be null\");\n        } else if (receiver.isNull()) {\n            throw new IllegalArgumentException(\"For instance methods, the receiver argument must not represent a null constant\");\n        }\n        AbstractEspressoSignature signature = getSignature();\n        int parameterCount = signature.getParameterCount(false);\n        if (parameterCount != arguments.length) {\n            throw new IllegalArgumentException(\"Expected \" + parameterCount + \" arguments, got \" + arguments.length);\n        }\n        Object[] args = new Object[arguments.length + (isConstructor() || !isStatic() ? 1 : 0)];\n        int outputArgumentOffset = 0;\n        EspressoExternalVMAccess access = getAccess();\n        if (isConstructor()) {\n            EspressoExternalResolvedInstanceType type = (EspressoExternalResolvedInstanceType) getDeclaringClass();\n            args[0] = access.unsafeAllocateInstance(type).getValue();\n            outputArgumentOffset = 1;\n        } else if (!isStatic()) {\n            if (!(receiver instanceof EspressoExternalObjectConstant objectConstant)) {\n                throw new IllegalArgumentException(\"Bad receiver: expected Object, got \" + arguments[0].getJavaKind());\n            }\n            args[0] = objectConstant.getValue();\n            outputArgumentOffset = 1;\n        }\n        for (int i = 0; i < parameterCount; i++) {\n            JavaConstant argument = arguments[i];\n            JavaKind argumentKind = argument.getJavaKind();","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaMethod.java#L278-L314","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: reflect-style call with receiver in args\nmethod.invoke(receiver, allArgsWithReceiver);\n\n// after\nJavaConstant[] params = Arrays.copyOfRange(allArgsWithReceiver, 1, allArgsWithReceiver.length);\nmethod.invoke(receiver, params);","handlingStrategy":"validation","validationCode":"int expected = method.getSignature().getParameterCount(false);\nif (expected != args.length) {\n    throw new IllegalStateException(method.getName() + \": expected \" + expected + \" args, got \" + args.length);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["espresso","jvmci","method-invocation","arity-mismatch","varargs"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}