oracle/graal · error · ElementException

NodeSuccessorList field must be annotated with @${Successor.

Error message

NodeSuccessorList field must be annotated with @${Successor.getSimpleName()}

What it means

NodeSuccessorList fields must be annotated with @Successor. A successor list without the annotation would hold control-flow edges the graph cannot see or maintain, so the NodeInfo processor rejects it at compile time. This is the control-flow counterpart of the NodeInputList rule and applies to every non-static, non-transient field in the node hierarchy.

Source

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

                            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");
                    }
                }
            }
            currentClazz = getSuperType(currentClazz);
        } while (!isObject(getSuperType(currentClazz).asType()));
    }

    private AnnotationMirror findAnnotationMirror(List<? extends AnnotationMirror> mirrors, TypeElement expectedAnnotationType) {
        for (AnnotationMirror mirror : mirrors) {
            if (sameType(mirror.getAnnotationType(), expectedAnnotationType.asType())) {
                return mirror;
            }
        }
        return null;
    }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Add @Successor to the NodeSuccessorList field.
  2. If the field is actually a value dependency, change its type to NodeInputList and use @Input/@OptionalInput.
  3. If it is not a graph edge, use a non-special list type or mark it transient/static.
  4. Rebuild to confirm.

Example fix

// before
protected NodeSuccessorList<FixedNode> blockSuccessors;

// after
@Successor
protected NodeSuccessorList<FixedNode> blockSuccessors;
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: isAssignableWithErasure(field, NodeSuccessorList) is true and @Successor is absent (GraphNodeVerifier.java:171-173). Example: 'protected NodeSuccessorList<FixedNode> branches;' without annotation.

Common situations: Adding a multi-target successor list (switch/loop nodes) and forgetting @Successor; annotating it with @Input by mistake; porting control-flow nodes between suites.

Related errors


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