oracle/graal · error · IllegalArgumentException
Annotation value type %s has no host class
Error message
Annotation value type %s has no host class
What it means
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.
Source
Thrown at compiler/src/jdk.graal.compiler.vmaccess/src/jdk/graal/compiler/vmaccess/HostAnnotationValueConverter.java:92
* @param annotationValue the annotation metadata to convert
* @param expectedType the annotation type to which the result must be assignable
* @param typeToClass maps JVMCI types to their corresponding host classes
* @return the converted annotation, or {@code null} when {@code annotationValue} is null
* @throws IllegalArgumentException if the annotation or one of its elements is incompatible
* with its declared type
*/
public static <T extends Annotation> T toAnnotation(AnnotationValue annotationValue, Class<T> expectedType, Function<ResolvedJavaType, Class<?>> typeToClass) {
if (annotationValue == null) {
return null;
}
Objects.requireNonNull(expectedType);
Objects.requireNonNull(typeToClass);
if (annotationValue.isError()) {
throw annotationValue.getError();
}
Class<?> actualType = typeToClass.apply(annotationValue.getAnnotationType());
if (actualType == null) {
throw new IllegalArgumentException("Annotation value type " + annotationValue.getAnnotationType().toJavaName() + " has no host class");
}
if (!actualType.isAnnotation()) {
throw new IllegalArgumentException("Annotation value type " + actualType.getName() + " is not an annotation interface");
}
if (!expectedType.isAssignableFrom(actualType)) {
throw new IllegalArgumentException("Annotation value type " + actualType.getName() + " is not assignable to " + expectedType.getName());
}
Class<? extends Annotation> annotationType = actualType.asSubclass(Annotation.class);
Annotation annotation = annotationValue.toAnnotation(annotationType, (value, type) -> createAnnotation(value, type, typeToClass));
return expectedType.cast(annotation);
}
/**
* Materializes a host-owned JDK annotation proxy from JVMCI annotation metadata.
*/
private static <T extends Annotation> T createAnnotation(AnnotationValue annotationValue, Class<T> annotationType, Function<ResolvedJavaType, Class<?>> typeToClass) {
Map<String, Object> memberValues = new LinkedHashMap<>();
Map<String, Object> annotationElements = annotationValue.getElements();View on GitHub (pinned to a66e9ccd1d)
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.
Example fix
// before Function<ResolvedJavaType, Class<?>> f = t -> JAVA_ONLY.get(t.toJavaName()); // null for com.foo.Bar // after Function<ResolvedJavaType, Class<?>> f = t -> Class.forName(t.toJavaName(), false, appLoader);
Defensive patterns
Strategy: validation
Validate before calling
ResolvedJavaType at = annotationValue.getAnnotationType();
if (typeToClass.apply(at) == null) { /* exclude or resolve the type before calling toAnnotation */ } Try / catch
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; } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Annotation value type %s is not an annotation interface
- Annotation class element type %s has no host class
- Annotation member %s.%s does not match declared type %s
- Annotation value type %s is not assignable to %s
- Unsupported annotation error element: %s
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/54759f93441d49a0.
Report an issue: GitHub.