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.

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)

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.