oracle/graal · error · IllegalArgumentException

Expected value kind {} but got {}

Error message

Expected value kind {} but got {}

What it means

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).

Source

Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalResolvedJavaField.java:149

            if (!(receiver instanceof EspressoExternalObjectConstant espressoReceiver)) {
                throw new IllegalArgumentException("Expected an espresso object receiver, got " + receiver.getClass().getName());
            }
            receiverValue = espressoReceiver.getValue();
        }

        JavaKind kind = getJavaKind();
        final Object boxed;
        if (kind == JavaKind.Object) {
            if (value.isNull()) {
                boxed = null;
            } else if (value instanceof EspressoExternalObjectConstant objConst) {
                boxed = objConst.getValue();
            } else {
                throw new IllegalArgumentException("Expected an espresso object constant, got " + value.getClass().getName());
            }
        } else {
            if (kind != value.getJavaKind()) {
                throw new IllegalArgumentException("Expected value kind " + kind + " but got " + value.getJavaKind());
            }
            boxed = value.asBoxedPrimitive();
        }

        getAccess().invokeJVMCIHelper("writeField", vmFieldMirror, receiverValue, boxed);
    }

    /**
     * Gets a guest {@link java.lang.reflect.Field} value associated with this field, creating it
     * first if necessary.
     */
    Value getReflectFieldMirror() {
        Value value = reflectFieldMirror;
        if (value == null) {
            value = getAccess().invokeJVMCIHelper("getReflectField", vmFieldMirror);
            reflectFieldMirror = value;
        }
        return value;

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. 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
  2. For integral widening, replicate the conversion yourself (e.g. JavaConstant.forLong(intConst.asInt()) for a long field)
  3. Log field.getName()+field.getJavaKind() next to value.getJavaKind() at the failure site to find the pass that mismatches kinds

Example fix

// before
field.writeValue(receiver, JavaConstant.forInt(size)); // field is long

// after
JavaKind fieldKind = field.getJavaKind();
JavaConstant converted = switch (fieldKind) {
    case Long -> JavaConstant.forLong(size);
    case Int -> JavaConstant.forInt(size);
    default -> throw new AssertionError("unsupported " + fieldKind);
};
field.writeValue(receiver, converted);
Defensive patterns

Strategy: validation

Validate before calling

JavaKind expected = field.getJavaKind();
JavaConstant v = switch (expected) {
    case Long -> JavaConstant.forLong(raw.asLong());
    case Int -> JavaConstant.forInt((int) raw.asLong());
    case Double -> JavaConstant.forDouble(raw.asDouble());
    case Float -> JavaConstant.forFloat((float) raw.asDouble());
    default -> raw;
};
assert v.getJavaKind() == expected;

Prevention

When it happens

Trigger: 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).

Common situations: 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().

Related errors


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