bazelbuild/bazel · error · OptionsParsingException

Tried to expand option too many times

Error message

Tried to expand option too many times

What it means

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.

Source

Thrown at src/main/java/com/google/devtools/common/options/OptionPriority.java:77

    return new OptionPriority(
        priority.priorityCategory,
        ImmutableList.<Integer>builder()
            .addAll(priority.priorityIndices.subList(0, lastElementPosition))
            .add(priority.priorityIndices.get(lastElementPosition) + 1)
            .build());
  }

  /**
   * Some options are expanded to other options, and the children options need to have their order
   * preserved while maintaining their position between the options that flank the parent option.
   *
   * @return the priority for the first child of the passed priority. This child's ordering can be
   *     tracked the same way that the parent's was.
   */
  public static OptionPriority getChildPriority(OptionPriority parentPriority)
      throws OptionsParsingException {
    if (parentPriority.alreadyExpanded) {
      throw new OptionsParsingException("Tried to expand option too many times");
    }
    // Prevent this option from being re-expanded.
    parentPriority.alreadyExpanded = true;

    // The child priority has 1 more level of nesting than its parent.
    return new OptionPriority(
        parentPriority.priorityCategory,
        ImmutableList.<Integer>builder().addAll(parentPriority.priorityIndices).add(0).build());
  }

  public PriorityCategory getPriorityCategory() {
    return priorityCategory;
  }

  @Override
  public int compareTo(OptionPriority o) {
    if (priorityCategory.equals(o.priorityCategory)) {
      for (int i = 0; i < priorityIndices.size() && i < o.priorityIndices.size(); ++i) {

View on GitHub (pinned to e6e199d060)

Solutions

  1. Flatten the expansion: make the parent option expand directly to the final leaf flags instead of expanding to another expansion option
  2. If you drive expansion programmatically, create a fresh priority context for each expansion round instead of reusing the parent's OptionPriority
  3. Audit custom OptionDefinition expansion lists for chained expansion options and remove the intermediate option

Example fix

// before
@Option(name = "aspect", expansion = {"experimental_nested"})
// after — expand directly to leaves
@Option(name = "aspect", expansion = {"--experimental_leaf_a", "--experimental_leaf_b"})
Defensive patterns

Strategy: validation

Validate before calling

// Before programmatic expansion, ensure the priority node is fresh
if (expandedPriorities.contains(parentPriority)) {
  throw new IllegalStateException("Refusing to re-expand priority; flatten expansion instead");
}
OptionsParserImplResult r = impl.parseArgsAsExpansionOfOption(option, source, args);

Try / catch

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'.

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14). Data as JSON: /api/errors/d827da5df11510fe. Report an issue: GitHub.