{"record":{"id":"0c163aef0812d741","repo":"oracle/graal","slug":"data-field-must-be-final-if-public","errorCode":null,"errorMessage":"Data field must be final if public","messagePattern":"Data field must be final if public","errorType":"validation","errorClass":"ElementException","httpStatus":null,"severity":"error","filePath":"compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/nodeinfo/processor/GraphNodeVerifier.java","lineNumber":175,"sourceCode":"                            throw new ElementException(field, \"Successor field must not be final\");\n                        }\n                        if (modifiers.contains(PUBLIC)) {\n                            throw new ElementException(field, \"Successor field must not be public\");\n                        }\n                    }\n\n                } else {\n                    if (isAssignableWithErasure(field, Node) && !field.getSimpleName().contentEquals(\"Null\")) {\n                        throw new ElementException(field, \"Node field must be annotated with @\" + Input.getSimpleName() + \", @\" + OptionalInput.getSimpleName() + \" or @\" + Successor.getSimpleName());\n                    }\n                    if (isAssignableWithErasure(field, NodeInputList)) {\n                        throw new ElementException(field, \"NodeInputList field must be annotated with @\" + Input.getSimpleName() + \" or @\" + OptionalInput.getSimpleName());\n                    }\n                    if (isAssignableWithErasure(field, NodeSuccessorList)) {\n                        throw new ElementException(field, \"NodeSuccessorList field must be annotated with @\" + Successor.getSimpleName());\n                    }\n                    if (modifiers.contains(PUBLIC) && !modifiers.contains(FINAL)) {\n                        throw new ElementException(field, \"Data field must be final if public\");\n                    }\n                }\n            }\n            currentClazz = getSuperType(currentClazz);\n        } while (!isObject(getSuperType(currentClazz).asType()));\n    }\n\n    private AnnotationMirror findAnnotationMirror(List<? extends AnnotationMirror> mirrors, TypeElement expectedAnnotationType) {\n        for (AnnotationMirror mirror : mirrors) {\n            if (sameType(mirror.getAnnotationType(), expectedAnnotationType.asType())) {\n                return mirror;\n            }\n        }\n        return null;\n    }\n\n    private boolean isObject(TypeMirror type) {\n        return sameType(object.asType(), type);","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/compiler/src/jdk.graal.compiler.processor/src/jdk/graal/compiler/nodeinfo/processor/GraphNodeVerifier.java#L157-L193","documentation":"Plain data fields (no @Input/@OptionalInput/@Successor, not Node/NodeInputList/NodeSuccessorList typed) that are public must be final. The node's generated meta-access and substitution logic treats public non-final fields as mutable state outside the graph model, which is unsupported; immutable public constants are fine. This is the classic '@NodeInfo data field' rule checked by GraphNodeVerifier at compile time.","triggerScenarios":"modifiers.contains(PUBLIC) && !modifiers.contains(FINAL) on an unannotated non-node field (GraphNodeVerifier.java:174-176). Example: 'public int offset;' or 'public Stamp stamp;' in a @NodeInfo class.","commonSituations":"Adding configuration/flag fields to a node and defaulting to public visibility; records-style classes pasted in; exposing cached values publicly without making them final.","solutions":["Make the public data field final and initialize it in the constructor.","Or reduce its visibility to protected/package-private if it must be mutable (and manage mutation via node methods).","Or model the value as an @Input/@OptionalInput edge if it is actually a node dependency.","Rebuild to confirm."],"exampleFix":"// before\npublic int offset;\n\n// after\npublic final int offset;","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make public data fields on nodes final and constructor-initialized.","For mutable node-local state, use protected/package-private fields updated via methods."],"tags":["java","graalvm","annotation-processing","graal-node","immutability","compile-time"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}