oracle/graal · error · IllegalArgumentException

Not an annotation type

Error message

Not an annotation type

What it means

After locating the include folder, findJNIHeaders() searches it (depth 2) for each required header name in INCLUDES (jni.h, jni_md.h and friends). If a header cannot be found it throws IllegalStateException. Note the message prints res[i] (the still-null/empty slot) instead of the missing name, so read the source INCLUDES array to know which file is actually missing.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueType.java:70

         * @interface Named { String value(); }
         *
         * @interface Anno { Named named() default @Named("foo"); }
         *
         * Creating the AnnotationValueType for Anno will recursively call getInstance to create the
         * AnnotationValueType for Named.
         */
        AnnotationValueType value = ANNOTATION_TYPES.get(annotationClass);
        if (value != null) {
            return value;
        }
        AnnotationValueType created = new AnnotationValueType(annotationClass);
        AnnotationValueType existing = ANNOTATION_TYPES.putIfAbsent(annotationClass, created);
        return existing != null ? existing : created;
    }

    private AnnotationValueType(ResolvedJavaType annotationClass) {
        if (!annotationClass.isAnnotation()) {
            throw new IllegalArgumentException("Not an annotation type");
        }

        ResolvedJavaMethod[] methods = annotationClass.getDeclaredMethods();

        memberTypes = new EconomicHashMap<>(methods.length + 1);
        memberDefaults = new EconomicHashMap<>(0);

        for (ResolvedJavaMethod method : methods) {
            if (method.isPublic() &&
                            method.isAbstract() &&
                            !method.isSynthetic()) {
                if (method.getSignature().getParameterCount(false) != 0) {
                    throw new IllegalArgumentException(method + " has params");
                }
                String name = method.getName();
                ResolvedJavaType memberType = method.getSignature().getReturnType(annotationClass).resolve(annotationClass);
                memberTypes.put(name, memberType);

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Check that $JAVA_HOME/include contains jni.h and a platform subfolder (linux/darwin/win32) with jni_md.h; reinstall the JDK-devel package if not.
  2. Point java.home at a complete, official JDK distribution.
  3. If the message is ambiguous (prints null), cross-check the INCLUDES array in JNI.java to identify the missing file.
Defensive patterns

Strategy: validation

Validate before calling

Path inc = Paths.get(System.getProperty("java.home"), "include");
for (String h : new String[]{"jni.h", "linux/jni_md.h"}) { // adjust platform dir for darwin/win32
    if (!Files.exists(inc.resolve(h))) {
        throw new IllegalStateException("Missing JNI header " + h + " under " + inc);
    }
}

Prevention

When it happens

Trigger: A JDK whose include/ exists but is missing platform headers (jni_md.h lives in include/linux or include/darwin and was not packaged); a partially installed or corrupted JDK; a nonstandard JDK layout where headers sit deeper than depth 2 from include/.

Common situations: Distro JDK packages that split headers across packages; hand-copied JDK directories that missed include/<platform>/ subfolders; stripped container images.

Related errors


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