{"record":{"id":"2620386d02943756","repo":"oracle/graal","slug":"expected-an-espresso-constant-got-a","errorCode":null,"errorMessage":"Expected an espresso constant got a {}","messagePattern":"Expected an espresso constant got a (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalSnippetReflectionProvider.java","lineNumber":86,"sourceCode":"            return new EspressoExternalObjectConstant(access, guestArray);\n        }\n        throw JVMCIError.shouldNotReachHere(\"Cannot create JavaConstant for external JVMCI: \" + clazz + \". Only primitive arrays are supported.\");\n    }\n\n    /**\n     * Converts selected guest constants to host objects.\n     * <p>\n     * This conversion is intentionally narrow: strings and byte arrays are supported for\n     * compatibility, while arbitrary guest objects are rejected.\n     */\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T asObject(Class<T> type, JavaConstant constant) {\n        if (constant.isNull() || !constant.getJavaKind().isObject()) {\n            return null;\n        }\n        if ((!(constant instanceof EspressoExternalObjectConstant objConstant))) {\n            throw new IllegalArgumentException(\"Expected an espresso constant got a \" + safeGetClass(constant));\n        }\n        Value value = objConstant.getValue();\n        Value metaObject = value.getMetaObject();\n        if (access.java_lang_String_class.equals(metaObject)) {\n            if (!type.isAssignableFrom(String.class)) {\n                return null;\n            }\n            return (T) value.asString();\n        }\n        if (access.byte_array_class.equals(metaObject)) {\n            if (!type.isAssignableFrom(byte[].class)) {\n                return null;\n            }\n            int size = Math.toIntExact(value.getArraySize());\n            byte[] result = new byte[size];\n            access.invokeJVMCIHelper(\"copyByteArray\", value, result);\n            return (T) result;\n        }","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso-compiler-stub/src/com.oracle.truffle.espresso.vmaccess/src/com/oracle/truffle/espresso/vmaccess/EspressoExternalSnippetReflectionProvider.java#L68-L104","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the JavaConstant was produced by the same EspressoExternalVMAccess/constant reflection provider instance you are reflecting with.","Check constant instanceof EspressoExternalObjectConstant before calling asObject, and skip/handle foreign constants separately.","If you need host-object reflection, use the host snippet reflection provider for host constants instead of the Espresso one."],"exampleFix":"// before\nString s = snippetReflection.asObject(String.class, constant);\n\n// after\nif (constant instanceof EspressoExternalObjectConstant esc) {\n    String s = snippetReflection.asObject(String.class, constant);\n} else {\n    String s = hostSnippetReflection.asObject(String.class, constant);\n}","handlingStrategy":"type-guard","validationCode":"if (!(constant instanceof EspressoExternalObjectConstant)) {\n    // constant is host or foreign; use the host snippet reflection instead\n}","typeGuard":"static boolean isEspressoConstant(JavaConstant c) {\n    return c instanceof EspressoExternalObjectConstant;\n}","tryCatchPattern":"catch (IllegalArgumentException e) when message starts with 'Expected an espresso constant' -> fall back to host snippet reflection; do not swallow silently.","preventionTips":["Keep one snippet reflection per provider and pass constants only to their own provider.","Centralize constant-to-host conversion behind a dispatcher that checks instanceof first.","In multi-context setups, tag constants with their context."],"tags":["jvmci","espresso","graalvm","snippet-reflection","constants"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}