oracle/graal · error · ElementException

Input field type must be an interface or assignable to Node

Error message

Input field type must be an interface or assignable to Node

What it means

For a single (non-list) input field annotated with @Input/@OptionalInput, the verifier requires the field's type to be either an interface or assignable to Node. Inputs are edges in the value-graph; a concrete class that is not a Node cannot participate in the graph, and non-interface types would break the type-erasure-based dispatch the generated code relies on. The processor throws this ElementException at compile time on the field.

Source

Thrown at compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/nodeinfo/processor/GraphNodeVerifier.java:135

                boolean isNonOptionalInput = findAnnotationMirror(annotations, Input) != null;
                boolean isOptionalInput = findAnnotationMirror(annotations, OptionalInput) != null;
                boolean isSuccessor = findAnnotationMirror(annotations, Successor) != null;

                if (isNonOptionalInput || isOptionalInput) {
                    if (findAnnotationMirror(annotations, Successor) != null) {
                        throw new ElementException(field, "Field cannot be both input and successor");
                    } else if (isNonOptionalInput && isOptionalInput) {
                        throw new ElementException(field, "Inputs must be either optional or non-optional");
                    } else if (isAssignableWithErasure(field, NodeInputList)) {
                        if (modifiers.contains(FINAL)) {
                            throw new ElementException(field, "Input list field must not be final");
                        }
                        if (modifiers.contains(PUBLIC)) {
                            throw new ElementException(field, "Input list field must not be public");
                        }
                    } else {
                        if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) {
                            throw new ElementException(field, "Input field type must be an interface or assignable to Node");
                        }
                        if (modifiers.contains(FINAL)) {
                            throw new ElementException(field, "Input field must not be final");
                        }
                        if (modifiers.contains(PUBLIC)) {
                            throw new ElementException(field, "Input field must not be public");
                        }
                    }
                } else if (isSuccessor) {
                    if (isAssignableWithErasure(field, NodeSuccessorList)) {
                        if (modifiers.contains(FINAL)) {
                            throw new ElementException(field, "Successor list field must not be final");
                        }
                        if (modifiers.contains(PUBLIC)) {
                            throw new ElementException(field, "Successor list field must not be public");
                        }
                    } else {
                        if (!isAssignableWithErasure(field, Node)) {

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Change the input field's type to an interface that the actual node implements, or to a type assignable to Node.
  2. If the value is real data rather than a graph edge, remove @Input/@OptionalInput and keep it as a final data field (optionally public+final).
  3. If the value is a constant used in code generation, consider @ConstantInput or making the class a NodeClass-registered node.
  4. Rebuild with mx build to confirm.

Example fix

// before
@Input
protected MyHelperNode helper; // MyHelperNode is a plain class

// after
@Input
protected ValueNode helper; // interface or Node subtype
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: A field with @Input or @OptionalInput whose erased type fails isAssignableWithErasure(field, Node) and whose declared type is not an interface kind (the check at GraphNodeVerifier.java:134). Typical trigger: '@Input protected MyConcreteHelperNode helper;' where MyConcreteHelperNode is a plain class not extending Node, or an input typed as a concrete non-Node class.

Common situations: Adding a plain utility/data class (not a Node subclass) as an @Input; inputting a concrete type like 'ConcreteStamp' that does not extend Node; forgetting to make a value type an interface when it is used as an input.

Related errors


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