{"record":{"id":"f877e52f662199b7","repo":"oracle/graal","slug":"input-field-must-not-be-final","errorCode":null,"errorMessage":"Input field must not be final","messagePattern":"Input field must not be final","errorType":"validation","errorClass":"ElementException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/nodeinfo/processor/GraphNodeVerifier.java","lineNumber":138,"sourceCode":"\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)) {\n                            throw new ElementException(field, \"Successor field must be a Node type\");\n                        }\n                        if (modifiers.contains(FINAL)) {","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/nodeinfo/processor/GraphNodeVerifier.java#L120-L156","documentation":"A single-valued input field (annotated @Input or @OptionalInput, type assignable to Node or an interface, not a NodeInputList) must not be final. The compiler runtime replaces input references in-place when edges are rewired (e.g. during canonicalization or when a node is replaced), so the field must stay assignable. The NodeInfo annotation processor raises this at compile time.","triggerScenarios":"scanFields() finds modifiers.contains(FINAL) on an @Input/@OptionalInput field in the non-NodeInputList branch (GraphNodeVerifier.java:137-139). Example: '@Input protected final ValueNode operand;'.","commonSituations":"Writing a new node with final 'value' fields out of habit from value-object design; IDE 'final where possible' refactorings; converting a DTO into a node; copying a constructor-initialized immutable field pattern.","solutions":["Drop final from the input field declaration.","Keep the field protected or package-private (public is separately rejected).","Initialize the field in the constructor; rely on updateUsages/replaceAtInput APIs for later rewiring.","Rebuild to confirm the processor error is gone."],"exampleFix":"// before\n@Input\nprotected final ValueNode x;\n\n// after\n@Input\nprotected ValueNode x;","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never mark @Input/@OptionalInput fields final; input edges are rewired by the runtime.","Disable IDE 'add final where possible' refactorings over node source directories.","Build with mx after adding inputs to a node so the processor validates immediately."],"tags":["java","graalvm","annotation-processing","graal-node","compile-time"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}