oracle/graal · error · ElementException

Inputs must be either optional or non-optional

Error message

Inputs must be either optional or non-optional

What it means

Thrown by GraphNodeVerifier when a Node field is annotated with both @Input and @OptionalInput simultaneously. Optionality is a single tri-state (absent, optional, non-optional), not a set of flags; annotating both makes the edge's nullability undefined and the generated node plumbing cannot pick one behavior, so the processor rejects it at compile time.

Source

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

        TypeElement currentClazz = node;
        do {
            for (VariableElement field : ElementFilter.fieldsIn(currentClazz.getEnclosedElements())) {
                Set<Modifier> modifiers = field.getModifiers();
                if (modifiers.contains(STATIC) || modifiers.contains(TRANSIENT)) {
                    continue;
                }

                List<? extends AnnotationMirror> annotations = field.getAnnotationMirrors();

                boolean isNonOptionalInput = findAnnotationMirror(annotations, Input) != null;
                boolean isOptionalInput = findAnnotationMirror(annotations, OptionalInput) != null;
                boolean isSuccessor = findAnnotationMirror(annotations, Successor) != null;

                if (isNonOptionalInput || isOptionalInput) {
                    if (findAnnotationMirror(annotations, Successor) != null) {
                        throw new ElementException(field, "Field cannot be both input and successor");
                    } else if (isNonOptionalInput && isOptionalInput) {
                        throw new ElementException(field, "Inputs must be either optional or non-optional");
                    } else if (isAssignableWithErasure(field, NodeInputList)) {
                        if (modifiers.contains(FINAL)) {
                            throw new ElementException(field, "Input list field must not be final");
                        }
                        if (modifiers.contains(PUBLIC)) {
                            throw new ElementException(field, "Input list field must not be public");
                        }
                    } else {
                        if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) {
                            throw new ElementException(field, "Input field type must be an interface or assignable to Node");
                        }
                        if (modifiers.contains(FINAL)) {
                            throw new ElementException(field, "Input field must not be final");
                        }
                        if (modifiers.contains(PUBLIC)) {
                            throw new ElementException(field, "Input field must not be public");
                        }
                    }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Keep exactly one annotation: @Input for a required edge, @OptionalInput for one that may be null.
  2. When making an input optional, also audit usages: optional inputs require null checks at use sites and allowedUsage changes.
  3. Remove the redundant annotation and rebuild so the annotation processor re-validates.

Example fix

// before
@Input
@OptionalInput
ValueNode value;

// after
@OptionalInput
ValueNode value;
Defensive patterns

Strategy: validation

Try / catch

Compile-time annotation-processing error; no runtime catch exists. Fix the field declaration and rebuild.

Prevention

When it happens

Trigger: A field declared as @Input @OptionalInput Node value; the verifier sets isNonOptionalInput and isOptionalInput booleans from annotation mirrors and throws when both are true (before the input/successor check would, since that is checked first only for the Successor conflict).

Common situations: Adding @OptionalInput to an existing @Input field during a refactor to permit null, and forgetting to remove @Input; IDE auto-complete inserting both; merging node classes where annotations from two variants accumulate.

Related errors


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