bazelbuild/bazel · error · OptionProcessorException
Can't set an option to be both an expansion option and have
Error message
Can't set an option to be both an expansion option and have implicit requirements.
What it means
Bazel's options annotation processor rejects @Option methods that are simultaneously expansion options (non-empty expansion attribute) and carry implicit requirements (non-empty implicitRequirements attribute). Both mechanisms rewrite the command line into other flags, and combining them creates ambiguous expansion semantics, so the processor forbids it at compile time.
Source
Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:438
private void checkOldCategoriesAreNotUsed(ExecutableElement method)
throws OptionProcessorException {
Option annotation = method.getAnnotation(Option.class);
if (DEPRECATED_CATEGORIES.contains(annotation.category())) {
throw new OptionProcessorException(
method,
"Documentation level is no longer read from the option category. Category \""
+ annotation.category()
+ "\" is disallowed, see OptionMetadataTags for the relevant tags.");
}
}
private void checkExpansionOptions(ExecutableElement method) throws OptionProcessorException {
Option annotation = method.getAnnotation(Option.class);
boolean isExpansion = annotation.expansion().length > 0;
boolean hasImplicitRequirements = annotation.implicitRequirements().length > 0;
if (isExpansion && hasImplicitRequirements) {
throw new OptionProcessorException(
method,
"Can't set an option to be both an expansion option and have implicit requirements.");
}
if (isExpansion || hasImplicitRequirements) {
if (annotation.allowMultiple()) {
throw new OptionProcessorException(
method,
"Can't set an option to accumulate multiple values and let it expand to other flags.");
}
}
}
private void checkNoDefaultValueForMultipleOption(ExecutableElement method)
throws OptionProcessorException {
Option annotation = method.getAnnotation(Option.class);
if (annotation.allowMultiple()
&& !annotation.defaultValue().equals("null")View on GitHub (pinned to e6e199d060)
Solutions
- Pick one mechanism: if the option should expand statically to other flags, keep expansion and delete implicitRequirements.
- If the option needs conditional/required companion flags, keep implicitRequirements and move the flags out of expansion (possibly into the implicit requirements list).
- If both sets of flags are truly needed, model them as two separate options, or fold all target flags into implicitRequirements.
- Recompile and confirm the processor accepts the option.
Example fix
// before
@Option(
name = "dual_mode",
defaultValue = "null",
documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
effectTags = {OptionEffectTag.EAGER},
expansion = {"--foo=1"},
implicitRequirements = {"--bar=2"}
)
// after (all companion flags as implicit requirements)
@Option(
name = "dual_mode",
defaultValue = "null",
documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
effectTags = {OptionEffectTag.EAGER},
implicitRequirements = {"--foo=1", "--bar=2"}
) Defensive patterns
Strategy: validation
Validate before calling
static void checkNotBothExpansionAndImplicit(String[] expansion,
String[] implicitRequirements) {
Preconditions.checkState(expansion.length == 0 || implicitRequirements.length == 0,
"An option cannot be both an expansion and have implicit requirements");
} Prevention
- Model one flag-rewriting mechanism per option: expansion for static rewrites, implicitRequirements for required companions.
- If a flag seems to need both, split it into two options.
When it happens
Trigger: Declaring @Option(..., expansion = {"--foo=1"}, implicitRequirements = {"--bar=2"}) — both arrays non-empty on the same option.
Common situations: Extending an existing expansion flag with implicit requirements (or vice versa) instead of choosing one mechanism; merging two option definitions during refactoring; misunderstanding that implicitRequirements is not a complement to expansion.
Related errors
- Can't set an option to accumulate multiple values and let it
- Option is an expansion flag with a static expansion, but doe
- Option includes UNKNOWN with other, known, effects. Please r
- Option includes NO_OP with other effects. This doesn't make
- Option has metadata tag %s but does not have category UNDOCU
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/5b28be3229f0ef8f.
Report an issue: GitHub.