{"record":{"id":"5b28be3229f0ef8f","repo":"bazelbuild/bazel","slug":"can-t-set-an-option-to-be-both-an-expansion-option","errorCode":null,"errorMessage":"Can't set an option to be both an expansion option and have implicit requirements.","messagePattern":"Can't set an option to be both an expansion option and have implicit requirements\\.","errorType":"validation","errorClass":"OptionProcessorException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java","lineNumber":438,"sourceCode":"  private void checkOldCategoriesAreNotUsed(ExecutableElement method)\n      throws OptionProcessorException {\n    Option annotation = method.getAnnotation(Option.class);\n    if (DEPRECATED_CATEGORIES.contains(annotation.category())) {\n      throw new OptionProcessorException(\n          method,\n          \"Documentation level is no longer read from the option category. Category \\\"\"\n              + annotation.category()\n              + \"\\\" is disallowed, see OptionMetadataTags for the relevant tags.\");\n    }\n  }\n\n  private void checkExpansionOptions(ExecutableElement method) throws OptionProcessorException {\n    Option annotation = method.getAnnotation(Option.class);\n    boolean isExpansion = annotation.expansion().length > 0;\n    boolean hasImplicitRequirements = annotation.implicitRequirements().length > 0;\n\n    if (isExpansion && hasImplicitRequirements) {\n      throw new OptionProcessorException(\n          method,\n          \"Can't set an option to be both an expansion option and have implicit requirements.\");\n    }\n\n    if (isExpansion || hasImplicitRequirements) {\n      if (annotation.allowMultiple()) {\n        throw new OptionProcessorException(\n            method,\n            \"Can't set an option to accumulate multiple values and let it expand to other flags.\");\n      }\n    }\n  }\n\n  private void checkNoDefaultValueForMultipleOption(ExecutableElement method)\n      throws OptionProcessorException {\n    Option annotation = method.getAnnotation(Option.class);\n    if (annotation.allowMultiple()\n        && !annotation.defaultValue().equals(\"null\")","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java#L420-L456","documentation":"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.","triggerScenarios":"Declaring @Option(..., expansion = {\"--foo=1\"}, implicitRequirements = {\"--bar=2\"}) — both arrays non-empty on the same option.","commonSituations":"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.","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."],"exampleFix":"// before\n@Option(\n  name = \"dual_mode\",\n  defaultValue = \"null\",\n  documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,\n  effectTags = {OptionEffectTag.EAGER},\n  expansion = {\"--foo=1\"},\n  implicitRequirements = {\"--bar=2\"}\n)\n// after (all companion flags as implicit requirements)\n@Option(\n  name = \"dual_mode\",\n  defaultValue = \"null\",\n  documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,\n  effectTags = {OptionEffectTag.EAGER},\n  implicitRequirements = {\"--foo=1\", \"--bar=2\"}\n)","handlingStrategy":"validation","validationCode":"static void checkNotBothExpansionAndImplicit(String[] expansion,\n                                              String[] implicitRequirements) {\n  Preconditions.checkState(expansion.length == 0 || implicitRequirements.length == 0,\n      \"An option cannot be both an expansion and have implicit requirements\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["java","bazel","annotation-processing","options","compile-time","expansion","implicit-requirements"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}