{"record":{"id":"2e0d6683b05b1787","repo":"oracle/graal","slug":"expected-value-kind-but-got-2e0d66","errorCode":null,"errorMessage":"Expected value kind {} but got {}","messagePattern":"Expected value kind (.+?) but 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/EspressoExternalResolvedJavaField.java","lineNumber":149,"sourceCode":"            if (!(receiver instanceof EspressoExternalObjectConstant espressoReceiver)) {\n                throw new IllegalArgumentException(\"Expected an espresso object receiver, got \" + receiver.getClass().getName());\n            }\n            receiverValue = espressoReceiver.getValue();\n        }\n\n        JavaKind kind = getJavaKind();\n        final Object boxed;\n        if (kind == JavaKind.Object) {\n            if (value.isNull()) {\n                boxed = null;\n            } else if (value instanceof EspressoExternalObjectConstant objConst) {\n                boxed = objConst.getValue();\n            } else {\n                throw new IllegalArgumentException(\"Expected an espresso object constant, got \" + value.getClass().getName());\n            }\n        } else {\n            if (kind != value.getJavaKind()) {\n                throw new IllegalArgumentException(\"Expected value kind \" + kind + \" but got \" + value.getJavaKind());\n            }\n            boxed = value.asBoxedPrimitive();\n        }\n\n        getAccess().invokeJVMCIHelper(\"writeField\", vmFieldMirror, receiverValue, boxed);\n    }\n\n    /**\n     * Gets a guest {@link java.lang.reflect.Field} value associated with this field, creating it\n     * first if necessary.\n     */\n    Value getReflectFieldMirror() {\n        Value value = reflectFieldMirror;\n        if (value == null) {\n            value = getAccess().invokeJVMCIHelper(\"getReflectField\", vmFieldMirror);\n            reflectFieldMirror = value;\n        }\n        return value;","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaField.java#L131-L167","documentation":"Thrown by EspressoExternalResolvedJavaField.writeValue when the field is primitive but the JavaKind of the value constant does not equal the field's kind. Unlike method invocation (which performs JLS widening conversions), field stores in this adapter are strict: an int field requires an Int-kind constant, a long field a Long-kind constant, etc. This mirrors Java store semantics (JLS 5.1.3 assignment conversion allows only identity or widening for primitives, but the adapter implements the exact-kind case and rejects everything else).","triggerScenarios":"Writing JavaConstant.forInt(1) into a long field, a Float constant into a double field, or a widened/narrowed constant whose stack kind differs from the field kind after JVMCI kind promotion (e.g. an Int constant representing a boolean/short/char slot).","commonSituations":"Lowering passes that box/unbox or promote constants to stack kinds before storing; snapshots or replays where the field resolution changed between runs (field type changed in the guest class); generic 'set field by name' tooling that guesses the constant kind from a boxed Object instead of field.getJavaKind().","solutions":["Convert the constant to the field's kind before writing: use JavaConstant conversion helpers or the field's getJavaKind() to drive forInt/forLong/forFloat/forDouble/forBoolean","For integral widening, replicate the conversion yourself (e.g. JavaConstant.forLong(intConst.asInt()) for a long field)","Log field.getName()+field.getJavaKind() next to value.getJavaKind() at the failure site to find the pass that mismatches kinds"],"exampleFix":"// before\nfield.writeValue(receiver, JavaConstant.forInt(size)); // field is long\n\n// after\nJavaKind fieldKind = field.getJavaKind();\nJavaConstant converted = switch (fieldKind) {\n    case Long -> JavaConstant.forLong(size);\n    case Int -> JavaConstant.forInt(size);\n    default -> throw new AssertionError(\"unsupported \" + fieldKind);\n};\nfield.writeValue(receiver, converted);","handlingStrategy":"validation","validationCode":"JavaKind expected = field.getJavaKind();\nJavaConstant v = switch (expected) {\n    case Long -> JavaConstant.forLong(raw.asLong());\n    case Int -> JavaConstant.forInt((int) raw.asLong());\n    case Double -> JavaConstant.forDouble(raw.asDouble());\n    case Float -> JavaConstant.forFloat((float) raw.asDouble());\n    default -> raw;\n};\nassert v.getJavaKind() == expected;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always drive constant reboxing from field.getJavaKind(), never from the value's current kind","Remember JVMCI stack promotion turns byte/short/char/boolean into Int — restore the source kind before a store","Field stores here are strict (no widening): convert explicitly like the method-invoke switch does"],"tags":["espresso","jvmci","javakind","field-write","primitive-conversion"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}