oracle/graal · error · RuntimeException

Could not load Graal NodeClass TYPE field for

Error message

Could not load Graal NodeClass TYPE field for 

What it means

NodeClass.getUnchecked reflectively reads the static field TYPE from a node class to obtain its NodeClass metadata. The RuntimeException wraps reflection failures: NoSuchFieldException (the class is not a Graal node or TYPE was never generated/initialized), IllegalAccessException/SecurityException (setAccessible(true) denied by JPMS or a security manager), or IllegalArgumentException. It is HostedOnly, i.e. used in the libgraal hosted runtime where node metadata is resolved via reflection.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/graph/NodeClass.java:117

    public static <T> NodeClass<T> create(Class<T> c) {
        assert getUnchecked(c) == null;
        Class<? super T> superclass = c.getSuperclass();
        NodeClass<? super T> nodeSuperclass = null;
        if (superclass != NODE_CLASS) {
            nodeSuperclass = get(superclass);
        }
        return new NodeClass<>(c, nodeSuperclass);
    }

    @SuppressWarnings("unchecked")
    @LibGraalSupport.HostedOnly
    private static <T> NodeClass<T> getUnchecked(Class<T> clazz) {
        try {
            Field field = clazz.getDeclaredField("TYPE");
            field.setAccessible(true);
            return (NodeClass<T>) field.get(null);
        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
            throw new RuntimeException("Could not load Graal NodeClass TYPE field for " + clazz, e);
        }
    }

    @LibGraalSupport.HostedOnly
    public static <T> NodeClass<T> get(Class<T> clazz) {
        NodeClass<T> result = getUnchecked(clazz);
        if (result == null && clazz != NODE_CLASS) {
            throw GraalError.shouldNotReachHere("TYPE field not initialized for class " + clazz.getTypeName()); // ExcludeFromJacocoGeneratedReport
        }
        return result;
    }

    private static final Class<?> NODE_CLASS = Node.class;
    private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
    private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;

    private static final AtomicInteger nextIterableId = new AtomicInteger();
    private static final AtomicInteger nextLeafId = new AtomicInteger();

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Ensure the class is a real Graal Node subclass whose static initializer creates TYPE (generated by the NodeInfo/NodeClass processor).
  2. Force class initialization before lookup: Class.forName(clazz.getName(), true, clazz.getClassLoader()).
  3. Add opens/exports for the node's package so setAccessible(true) is permitted (--add-opens java.base/... or module-info opens).
  4. Verify you are passing the node class you think you are (log clazz.getName()) and that only one classloader loaded it.

Example fix

// before
NodeClass<MyNode> nc = NodeClass.get(MyNode.class); // TYPE not initialized -> wrap of NoSuchFieldException

// after
Class.forName("com.example.MyNode", true, MyNode.class.getClassLoader()); // run static init
NodeClass<MyNode> nc = NodeClass.get(MyNode.class);
Defensive patterns

Strategy: try-catch

Validate before calling

try {
    Field f = clazz.getDeclaredField("TYPE");
    f.setAccessible(true);
    if (f.get(null) == null) throw new IllegalStateException("TYPE not initialized: " + clazz);
} catch (ReflectiveOperationException | SecurityException e) {
    // initialize or fix module opens before calling NodeClass.get
    Class.forName(clazz.getName(), true, clazz.getClassLoader());
}

Type guard

static boolean hasNodeClassMetadata(Class<?> c) {
    try {
        Field f = c.getDeclaredField("TYPE");
        f.setAccessible(true);
        return f.get(null) != null;
    } catch (ReflectiveOperationException | SecurityException e) {
        return false;
    }
}

Try / catch

try {
    NodeClass<T> nc = NodeClass.get(clazz);
} catch (RuntimeException e) {
    if (e.getCause() instanceof NoSuchFieldException) {
        throw new IllegalStateException(clazz + " is not a Graal node class (no TYPE field)", e);
    }
    if (e.getCause() instanceof SecurityException || e.getCause() instanceof IllegalAccessException) {
        throw new IllegalStateException("Reflection blocked: add --add-opens for " + clazz.getPackage().getName(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling NodeClass.get(clazz) where clazz has no public/static TYPE field (not a Node subclass, or class-level initialization not run), or running under a module policy that blocks deep reflection into the node's package. Also classloader tricks that re-load node classes without running their static initializers.

Common situations: Custom node classes whose static initializer did not run before metadata lookup. Strict JPMS builds or --illegal-access=deny style configurations that block setAccessible. Passing arbitrary classes (e.g. Object.class) into NodeClass.get instead of real node classes. Version skew between a node library and the compiler expecting a TYPE field.

Related errors


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