{"record":{"id":"091a287c1821ddfd","repo":"oracle/graal","slug":"for-instance-methods-the-receiver-argument-must-n-091a28","errorCode":null,"errorMessage":"For instance methods, the receiver argument must not represent a null constant","messagePattern":"For instance methods, the receiver argument must not represent a null constant","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":291,"sourceCode":"    }\n\n    @Override\n    protected int hashCode0() {\n        return vmMethodMirror.hashCode();\n    }\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();","sourceCodeStart":273,"sourceCodeEnd":309,"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#L273-L309","documentation":"Thrown by EspressoExternalResolvedJavaMethod.invoke when an instance method is invoked with a JavaConstant that represents null (isNull() == true) rather than a Java null reference. The adapter distinguishes a missing receiver (NPE, previous guard) from a present-but-null constant: even if you wrap null in a constant object, interop execution on a null guest Value is impossible, so it rejects with IllegalArgumentException. This catches constants produced by JavaConstant.NULL_POINTER or equivalent null-representing constants from another backend.","triggerScenarios":"Passing JavaConstant.NULL_POINTER (or a foreign backend's null constant) as the receiver to an instance method invoke; constants obtained from ConstantReflectionProvider forObject(null)-style APIs; defaulted constants (isDefaultForKind) reused as receivers.","commonSituations":"Uniform constant pipelines that represent 'absent object' as a null constant instead of a Java null; replayer/snapshot tools that serialize receivers and deserialize null as a constant; guest code that legitimately calls a method on null and the harness forwards the null constant verbatim.","solutions":["Convert null-representing constants to a Java null reference before calling invoke (receiver.isNull() ? null : receiver)","If the goal is a guest NPE, execute through the guest polyglot Value API rather than the JVMCI adapter","Audit producers that return JavaConstant.NULL_POINTER where callers expect nullable Java references"],"exampleFix":"// before\nJavaConstant receiver = provider.forObject(null); // NULL_POINTER constant\nmethod.invoke(receiver, args);\n\n// after\nJavaConstant receiver = provider.forObject(null);\nmethod.invoke(receiver.isNull() ? null : receiver, args); // adapter NPE path is explicit","handlingStrategy":"validation","validationCode":"if (receiver != null && receiver.isNull()) {\n    throw new IllegalStateException(\"null constant receiver for \" + method.getName() + \" — pass Java null or fix upstream\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize null-representing constants to Java null before invoke","Do not use JavaConstant.NULL_POINTER or foreign null constants as receivers","Distinguish 'no receiver' (static/constructor contract) from 'null receiver' (always invalid here) in your calling conventions"],"tags":["espresso","jvmci","method-invocation","null-constant","receiver-contract"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}