{"record":{"id":"54759f93441d49a0","repo":"oracle/graal","slug":"annotation-value-type-s-has-no-host-class","errorCode":null,"errorMessage":"Annotation value type %s has no host class","messagePattern":"Annotation value type (.+?) has no host class","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler.vmaccess/src/jdk/graal/compiler/vmaccess/HostAnnotationValueConverter.java","lineNumber":92,"sourceCode":"     * @param annotationValue the annotation metadata to convert\n     * @param expectedType the annotation type to which the result must be assignable\n     * @param typeToClass maps JVMCI types to their corresponding host classes\n     * @return the converted annotation, or {@code null} when {@code annotationValue} is null\n     * @throws IllegalArgumentException if the annotation or one of its elements is incompatible\n     *             with its declared type\n     */\n    public static <T extends Annotation> T toAnnotation(AnnotationValue annotationValue, Class<T> expectedType, Function<ResolvedJavaType, Class<?>> typeToClass) {\n        if (annotationValue == null) {\n            return null;\n        }\n        Objects.requireNonNull(expectedType);\n        Objects.requireNonNull(typeToClass);\n        if (annotationValue.isError()) {\n            throw annotationValue.getError();\n        }\n        Class<?> actualType = typeToClass.apply(annotationValue.getAnnotationType());\n        if (actualType == null) {\n            throw new IllegalArgumentException(\"Annotation value type \" + annotationValue.getAnnotationType().toJavaName() + \" has no host class\");\n        }\n        if (!actualType.isAnnotation()) {\n            throw new IllegalArgumentException(\"Annotation value type \" + actualType.getName() + \" is not an annotation interface\");\n        }\n        if (!expectedType.isAssignableFrom(actualType)) {\n            throw new IllegalArgumentException(\"Annotation value type \" + actualType.getName() + \" is not assignable to \" + expectedType.getName());\n        }\n        Class<? extends Annotation> annotationType = actualType.asSubclass(Annotation.class);\n        Annotation annotation = annotationValue.toAnnotation(annotationType, (value, type) -> createAnnotation(value, type, typeToClass));\n        return expectedType.cast(annotation);\n    }\n\n    /**\n     * Materializes a host-owned JDK annotation proxy from JVMCI annotation metadata.\n     */\n    private static <T extends Annotation> T createAnnotation(AnnotationValue annotationValue, Class<T> annotationType, Function<ResolvedJavaType, Class<?>> typeToClass) {\n        Map<String, Object> memberValues = new LinkedHashMap<>();\n        Map<String, Object> annotationElements = annotationValue.getElements();","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler.vmaccess/src/jdk/graal/compiler/vmaccess/HostAnnotationValueConverter.java#L74-L110","documentation":"HostAnnotationValueConverter.toAnnotation resolves the annotation's ResolvedJavaType to a host Class via the caller-supplied typeToClass function; if that function returns null for the annotation type itself, this IllegalArgumentException is thrown naming the type. It means the type lookup/mapping you provided cannot find a host class for an annotation type that actually has elements to convert.","triggerScenarios":"Calling toAnnotation with a typeToClass implementation that returns null for the annotation's own type — e.g. a lookup restricted to a specific classloader that cannot see the annotation, or that only maps a whitelist of types.","commonSituations":"Custom classloader hierarchies (embedded/isolated loads), snapshot-replay where the annotation type was not recorded, or a converter configured to map only java.* types while the annotation lives in a jdk.internal.* or application package.","solutions":["Extend the typeToClass function to resolve the named annotation type (delegate to Class.forName with the right loader, or a JVMCI host-mapping service).","Ensure the classloader used for lookup can see the annotation interface (add the containing module/jar).","If the type genuinely has no host class, filter such AnnotationValues out before conversion instead of calling toAnnotation.","Check annotationValue.isError() first — error values carry their own exception path."],"exampleFix":"// before\nFunction<ResolvedJavaType, Class<?>> f = t -> JAVA_ONLY.get(t.toJavaName()); // null for com.foo.Bar\n// after\nFunction<ResolvedJavaType, Class<?>> f = t -> Class.forName(t.toJavaName(), false, appLoader);","handlingStrategy":"validation","validationCode":"ResolvedJavaType at = annotationValue.getAnnotationType();\nif (typeToClass.apply(at) == null) { /* exclude or resolve the type before calling toAnnotation */ }","typeGuard":null,"tryCatchPattern":"try { HostAnnotationValueConverter.toAnnotation(av, Expected.class, fn); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"no host class\")) { /* widen fn's loader/search set */ } else throw e; }","preventionTips":["Make typeToClass fall back to Class.forName with the right loader for unknown types.","Ensure annotation interfaces are visible to the lookup loader.","Check annotationValue.isError() before conversion."],"tags":["graalvm","jvmci","annotations","classloading"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}