oracle/graal · error · ElementException

Successor field must not be final

Error message

Successor field must not be final

What it means

Single-valued @Successor fields (type assignable to Node, not a list) must not be final. The runtime rewrites successor references during CFG transformations (e.g. replacing a fixed node, deleting branches), which requires the field to be assignable. The NodeInfo annotation processor rejects final successor fields at compile time.

Solutions

  1. Remove final from the successor field.
  2. Assign it in the constructor and let graph transformations mutate it via setNext-style methods.
  3. Keep visibility protected or package-private.
  4. Rebuild to confirm.

Example fix

// before
@Successor
protected final FixedWithNextNode next;

// after
@Successor
protected FixedWithNextNode next;
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: modifiers.contains(FINAL) on a @Successor field in the non-NodeSuccessorList branch (GraphNodeVerifier.java:156-158). Example: '@Successor protected final FixedWithNextNode next;'.

Common situations: Writing fixed nodes with an immutable 'next' pointer; IDE final refactors applied broadly; converting a builder-style class into a node.

Related errors


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

Appendix: source

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

                        }
                        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)) {
                            throw new ElementException(field, "Successor field must be a Node type");
                        }
                        if (modifiers.contains(FINAL)) {
                            throw new ElementException(field, "Successor field must not be final");
                        }
                        if (modifiers.contains(PUBLIC)) {
                            throw new ElementException(field, "Successor field must not be public");
                        }
                    }

                } else {
                    if (isAssignableWithErasure(field, Node) && !field.getSimpleName().contentEquals("Null")) {
                        throw new ElementException(field, "Node field must be annotated with @" + Input.getSimpleName() + ", @" + OptionalInput.getSimpleName() + " or @" + Successor.getSimpleName());
                    }
                    if (isAssignableWithErasure(field, NodeInputList)) {
                        throw new ElementException(field, "NodeInputList field must be annotated with @" + Input.getSimpleName() + " or @" + OptionalInput.getSimpleName());
                    }
                    if (isAssignableWithErasure(field, NodeSuccessorList)) {
                        throw new ElementException(field, "NodeSuccessorList field must be annotated with @" + Successor.getSimpleName());
                    }
                    if (modifiers.contains(PUBLIC) && !modifiers.contains(FINAL)) {
                        throw new ElementException(field, "Data field must be final if public");

View on GitHub (pinned to a66e9ccd1d)