{"record":{"id":"d827da5df11510fe","repo":"bazelbuild/bazel","slug":"tried-to-expand-option-too-many-times","errorCode":null,"errorMessage":"Tried to expand option too many times","messagePattern":"Tried to expand option too many times","errorType":"exception","errorClass":"OptionsParsingException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/google/devtools/common/options/OptionPriority.java","lineNumber":77,"sourceCode":"    return new OptionPriority(\n        priority.priorityCategory,\n        ImmutableList.<Integer>builder()\n            .addAll(priority.priorityIndices.subList(0, lastElementPosition))\n            .add(priority.priorityIndices.get(lastElementPosition) + 1)\n            .build());\n  }\n\n  /**\n   * Some options are expanded to other options, and the children options need to have their order\n   * preserved while maintaining their position between the options that flank the parent option.\n   *\n   * @return the priority for the first child of the passed priority. This child's ordering can be\n   *     tracked the same way that the parent's was.\n   */\n  public static OptionPriority getChildPriority(OptionPriority parentPriority)\n      throws OptionsParsingException {\n    if (parentPriority.alreadyExpanded) {\n      throw new OptionsParsingException(\"Tried to expand option too many times\");\n    }\n    // Prevent this option from being re-expanded.\n    parentPriority.alreadyExpanded = true;\n\n    // The child priority has 1 more level of nesting than its parent.\n    return new OptionPriority(\n        parentPriority.priorityCategory,\n        ImmutableList.<Integer>builder().addAll(parentPriority.priorityIndices).add(0).build());\n  }\n\n  public PriorityCategory getPriorityCategory() {\n    return priorityCategory;\n  }\n\n  @Override\n  public int compareTo(OptionPriority o) {\n    if (priorityCategory.equals(o.priorityCategory)) {\n      for (int i = 0; i < priorityIndices.size() && i < o.priorityIndices.size(); ++i) {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/com/google/devtools/common/options/OptionPriority.java#L59-L95","documentation":"OptionPriority.getChildPriority refuses to compute a child priority for an OptionPriority that has already been expanded once. Expansion of an option into child options may only happen one level deep per priority node; the alreadyExpanded flag is set on the first expansion and any second call fails fast instead of producing unbounded or ambiguous ordering.","triggerScenarios":"Calling OptionsParser.parseArgsAsExpansionOfOption (or OptionPriority.getChildPriority) twice for options that share the same OptionPriority instance — typically an option whose expansion itself contains an expandable option, i.e. nested/chained expansions through the same priority object.","commonSituations":"Defining an @Option(expansion = {...}) whose expansion list contains another expansion option; library code that re-expands the same args in a second parsing round using the stored priority.","solutions":["Flatten the expansion: make the parent option expand directly to the final leaf flags instead of expanding to another expansion option","If you drive expansion programmatically, create a fresh priority context for each expansion round instead of reusing the parent's OptionPriority","Audit custom OptionDefinition expansion lists for chained expansion options and remove the intermediate option"],"exampleFix":"// before\n@Option(name = \"aspect\", expansion = {\"experimental_nested\"})\n// after — expand directly to leaves\n@Option(name = \"aspect\", expansion = {\"--experimental_leaf_a\", \"--experimental_leaf_b\"})","handlingStrategy":"validation","validationCode":"// Before programmatic expansion, ensure the priority node is fresh\nif (expandedPriorities.contains(parentPriority)) {\n  throw new IllegalStateException(\"Refusing to re-expand priority; flatten expansion instead\");\n}\nOptionsParserImplResult r = impl.parseArgsAsExpansionOfOption(option, source, args);","typeGuard":null,"tryCatchPattern":"Wrap parseArgsAsExpansionOfOption in try/catch for OptionsParsingException and surface 'chained expansion' as the likely cause when the message is 'Tried to expand option too many times'.","preventionTips":["Never define an expansion option that expands to another expansion option","Keep expansion lists flat — leaf flags only","When driving multiple expansion rounds, track which OptionPriority objects were already used"],"tags":["bazel","options","expansion","flag-parsing","priority"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}