{"record":{"id":"755a15876911800f","repo":"oracle/graal","slug":"input-field-type-must-be-an-interface-or-assignabl","errorCode":null,"errorMessage":"Input field type must be an interface or assignable to Node","messagePattern":"Input field type must be an interface or assignable to Node","errorType":"validation","errorClass":"ElementException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/nodeinfo/processor/GraphNodeVerifier.java","lineNumber":135,"sourceCode":"                boolean isNonOptionalInput = findAnnotationMirror(annotations, Input) != null;\n                boolean isOptionalInput = findAnnotationMirror(annotations, OptionalInput) != null;\n                boolean isSuccessor = findAnnotationMirror(annotations, Successor) != null;\n\n                if (isNonOptionalInput || isOptionalInput) {\n                    if (findAnnotationMirror(annotations, Successor) != null) {\n                        throw new ElementException(field, \"Field cannot be both input and successor\");\n                    } else if (isNonOptionalInput && isOptionalInput) {\n                        throw new ElementException(field, \"Inputs must be either optional or non-optional\");\n                    } else if (isAssignableWithErasure(field, NodeInputList)) {\n                        if (modifiers.contains(FINAL)) {\n                            throw new ElementException(field, \"Input list field must not be final\");\n                        }\n                        if (modifiers.contains(PUBLIC)) {\n                            throw new ElementException(field, \"Input list field must not be public\");\n                        }\n                    } else {\n                        if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) {\n                            throw new ElementException(field, \"Input field type must be an interface or assignable to Node\");\n                        }\n                        if (modifiers.contains(FINAL)) {\n                            throw new ElementException(field, \"Input field must not be final\");\n                        }\n                        if (modifiers.contains(PUBLIC)) {\n                            throw new ElementException(field, \"Input field must not be public\");\n                        }\n                    }\n                } else if (isSuccessor) {\n                    if (isAssignableWithErasure(field, NodeSuccessorList)) {\n                        if (modifiers.contains(FINAL)) {\n                            throw new ElementException(field, \"Successor list field must not be final\");\n                        }\n                        if (modifiers.contains(PUBLIC)) {\n                            throw new ElementException(field, \"Successor list field must not be public\");\n                        }\n                    } else {\n                        if (!isAssignableWithErasure(field, Node)) {","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/nodeinfo/processor/GraphNodeVerifier.java#L117-L153","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Change the input field's type to an interface that the actual node implements, or to a type assignable to Node.","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).","If the value is a constant used in code generation, consider @ConstantInput or making the class a NodeClass-registered node.","Rebuild with mx build to confirm."],"exampleFix":"// before\n@Input\nprotected MyHelperNode helper; // MyHelperNode is a plain class\n\n// after\n@Input\nprotected ValueNode helper; // interface or Node subtype","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use interfaces (like ValueNode) or Node subtypes as the declared type of every @Input field.","Reserve @Input for graph edges; plain data belongs in final fields without node annotations.","Model new node inputs after existing nodes' input declarations."],"tags":["java","graalvm","annotation-processing","graal-node","type-system","compile-time"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}