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
- Ensure the class is a real Graal Node subclass whose static initializer creates TYPE (generated by the NodeInfo/NodeClass processor).
- Force class initialization before lookup: Class.forName(clazz.getName(), true, clazz.getClassLoader()).
- Add opens/exports for the node's package so setAccessible(true) is permitted (--add-opens java.base/... or module-info opens).
- 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
- Only pass classes generated by the Graal annotation processor into NodeClass.get.
- In JPMS deployments, open the packages containing your node classes to the compiler.
- Ensure node classes are initialized (referenced/Class.forName) before hosted-time metadata lookup.
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
- No class for
- Edge
- Graph was permanetly frozen.
- unknown verbosity:
- NodeBitMap was modified between the calls to hasNext() and n
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/89b405120cf62a21.
Report an issue: GitHub.