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.

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.

Appendix: 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)