bazelbuild/bazel · error · OptionProcessorException
@Option method must be abstract
Error message
@Option method must be abstract
What it means
The options annotation processor requires @Option-annotated interface methods to be abstract — no default bodies — because the processor generates the implementation itself. A method with a default implementation (or otherwise non-abstract) fails this check at compile time immediately after the visibility check.
Source
Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:332
option.capitalizedFieldName,
option.hasSetterInBase ? "@Override" : "");
}
out.println("}");
}
} catch (IOException e) {
messager.printMessage(
Diagnostic.Kind.ERROR,
"Failed to generate implementation for " + className + ": " + e.getMessage());
}
}
private void checkMethodOption(ExecutableElement method) throws OptionProcessorException {
if (!method.getModifiers().contains(Modifier.PUBLIC)) {
throw new OptionProcessorException(method, "@Option method must be public");
}
if (!method.getModifiers().contains(Modifier.ABSTRACT)) {
throw new OptionProcessorException(method, "@Option method must be abstract");
}
String methodName = method.getSimpleName().toString();
if (!methodName.startsWith("get")
|| methodName.length() < 4
|| !Character.isUpperCase(methodName.charAt(3))) {
throw new OptionProcessorException(
method, "Annotated method name must start with 'get' followed by an uppercase letter");
}
checkOptionName(method);
checkOldCategoriesAreNotUsed(method);
checkExpansionOptions(method);
checkConverter(method);
checkEffectTagRationality(method);
checkMetadataTagAndCategoryRationality(method);
checkNoDefaultValueForMultipleOption(method);
checkDeprecated(method);View on GitHub (pinned to e6e199d060)
Solutions
- Remove the method body and the default keyword, leaving only the signature
- Express the default via @Option(defaultValue = ...) on the annotation instead
- Recompile to confirm the processor accepts the interface
Example fix
// before
@Option(name = "foo", defaultValue = "x", effectTags = {OptionEffectTag.NO_OP})
default String getFoo() { return "x"; }
// after
@Option(name = "foo", defaultValue = "x", effectTags = {OptionEffectTag.NO_OP})
String getFoo(); Defensive patterns
Strategy: validation
Validate before calling
// Fail tests that find default bodies on @Option methods
for (var m : MyOptions.class.getMethods()) {
if (m.isAnnotationPresent(Option.class) && !Modifier.isAbstract(m.getModifiers())) {
throw new AssertionError("@Option method must be abstract: " + m);
}
} Prevention
- Put defaults in @Option(defaultValue = ...), never in method bodies
- Avoid IDE 'extract interface' refactors on option classes without reviewing generated defaults
When it happens
Trigger: Giving an @Option interface method a default body: `default String getFoo() { return "x"; }`, or converting an existing interface where the getter already has a default.
Common situations: Refactoring old option classes where defaults lived in getters; IDE 'extract interface' producing default methods; copy-pasting a concrete getter into a new options interface.
Related errors
- @Option method must be public
- Annotated method name must start with 'get' followed by an u
- Option must have an actual name.
- Options that are used on the command line as flags must have
- Option does not list at least one OptionEffectTag. If the op
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/6128753b0f5ffa40.
Report an issue: GitHub.