oracle/graal · error · IllegalArgumentException

Expected an espresso constant got a {}

Error message

Expected an espresso constant got a {}

What it means

EspressoExternalSnippetReflectionProvider.asObject(type, constant) converts guest Espresso constants to host objects, but only accepts EspressoExternalObjectConstant instances. Passing a constant produced by a different JVMCI constant provider (e.g. the host HotSpot provider) violates that boundary and throws IllegalArgumentException. The narrow surface is intentional: only guest strings and byte arrays can be materialized on the host.

Source

Thrown at espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalSnippetReflectionProvider.java:86

            return new EspressoExternalObjectConstant(access, guestArray);
        }
        throw JVMCIError.shouldNotReachHere("Cannot create JavaConstant for external JVMCI: " + clazz + ". Only primitive arrays are supported.");
    }

    /**
     * Converts selected guest constants to host objects.
     * <p>
     * This conversion is intentionally narrow: strings and byte arrays are supported for
     * compatibility, while arbitrary guest objects are rejected.
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> T asObject(Class<T> type, JavaConstant constant) {
        if (constant.isNull() || !constant.getJavaKind().isObject()) {
            return null;
        }
        if ((!(constant instanceof EspressoExternalObjectConstant objConstant))) {
            throw new IllegalArgumentException("Expected an espresso constant got a " + safeGetClass(constant));
        }
        Value value = objConstant.getValue();
        Value metaObject = value.getMetaObject();
        if (access.java_lang_String_class.equals(metaObject)) {
            if (!type.isAssignableFrom(String.class)) {
                return null;
            }
            return (T) value.asString();
        }
        if (access.byte_array_class.equals(metaObject)) {
            if (!type.isAssignableFrom(byte[].class)) {
                return null;
            }
            int size = Math.toIntExact(value.getArraySize());
            byte[] result = new byte[size];
            access.invokeJVMCIHelper("copyByteArray", value, result);
            return (T) result;
        }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Ensure the JavaConstant was produced by the same EspressoExternalVMAccess/constant reflection provider instance you are reflecting with.
  2. Check constant instanceof EspressoExternalObjectConstant before calling asObject, and skip/handle foreign constants separately.
  3. If you need host-object reflection, use the host snippet reflection provider for host constants instead of the Espresso one.

Example fix

// before
String s = snippetReflection.asObject(String.class, constant);

// after
if (constant instanceof EspressoExternalObjectConstant esc) {
    String s = snippetReflection.asObject(String.class, constant);
} else {
    String s = hostSnippetReflection.asObject(String.class, constant);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(constant instanceof EspressoExternalObjectConstant)) {
    // constant is host or foreign; use the host snippet reflection instead
}

Type guard

static boolean isEspressoConstant(JavaConstant c) {
    return c instanceof EspressoExternalObjectConstant;
}

Try / catch

catch (IllegalArgumentException e) when message starts with 'Expected an espresso constant' -> fall back to host snippet reflection; do not swallow silently.

Prevention

When it happens

Trigger: Calling snippetReflection.asObject(String.class, c) where c came from another provider (HotSpotConstantReflectionProvider, a different Espresso context, or JavaConstant.forObject on a host object); also non-object kinds filtered earlier return null, but wrong-provider object constants throw here.

Common situations: Mixing host-compiled constants with Espresso guest constants in a Graal snippet substitution; multi-context setups where two Espresso VMs each produce constants and the wrong snippet reflection is used; upgrading code that previously passed raw host objects.

Related errors


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