bazelbuild/bazel · error · OptionProcessorException

Option does not list at least one OptionEffectTag. If the op

Error message

Option does not list at least one OptionEffectTag. If the option has no effect, please be explicit and add NO_OP. Otherwise, add a tag representing its effect.

What it means

Every @Option must declare at least one OptionEffectTag in its annotation — the machine-readable description of what setting the flag affects, used for option filtering and documentation. Zero tags fails this check; the message tells you to either declare a real effect or explicitly mark NO_OP when the flag truly has no effect.

Source

Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:376

    }

    if (!ImmutableList.copyOf(annotation.metadataTags()).contains(OptionMetadataTag.INTERNAL)) {
      if (!Pattern.matches("([\\w:-])*", optionName)) {
        // Ideally, this would be just \w, but - and : are needed for legacy options. We can lie in
        // the error though, no harm in encouraging good behavior.
        throw new OptionProcessorException(
            method,
            "Options that are used on the command line as flags must have names made from word "
                + "characters only.");
      }
    }
  }

  private void checkEffectTagRationality(ExecutableElement method) throws OptionProcessorException {
    Option annotation = method.getAnnotation(Option.class);
    OptionEffectTag[] effectTags = annotation.effectTags();
    if (effectTags.length < 1) {
      throw new OptionProcessorException(
          method,
          "Option does not list at least one OptionEffectTag. If the option has no effect, "
              + "please be explicit and add NO_OP. Otherwise, add a tag representing its effect.");
    } else if (effectTags.length > 1) {
      // If there are more than 1 tag, make sure that NO_OP and UNKNOWN is not one of them.
      // These don't make sense if other effects are listed.
      ImmutableList<OptionEffectTag> tags = ImmutableList.copyOf(effectTags);
      if (tags.contains(OptionEffectTag.UNKNOWN)) {
        throw new OptionProcessorException(
            method,
            "Option includes UNKNOWN with other, known, effects. Please remove UNKNOWN from "
                + "the list.");
      }
      if (tags.contains(OptionEffectTag.NO_OP)) {
        throw new OptionProcessorException(
            method,
            "Option includes NO_OP with other effects. This doesn't make much sense. Please "
                + "remove NO_OP or the actual effects from the list, whichever is correct.");

View on GitHub (pinned to e6e199d060)

Solutions

  1. Pick accurate tags from OptionEffectTag (e.g. EAGERNESS_FOR_OUTPUT, EXECUTION_STRATEGY, LOADING_AND_ANALYSIS, UNKNOWN) matching the flag's real effect
  2. If the flag genuinely does nothing (deprecated placeholder, marker), declare effectTags = {OptionEffectTag.NO_OP}
  3. Note the sibling rule: NO_OP and UNKNOWN cannot be combined with other tags

Example fix

// before
@Option(name = "foo", defaultValue = "x")
String getFoo();
// after
@Option(name = "foo", defaultValue = "x", effectTags = {OptionEffectTag.NO_OP})
String getFoo();
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every @Option declares at least one effect tag
for (var m : MyOptions.class.getMethods()) {
  Option o = m.getAnnotation(Option.class);
  if (o != null && o.effectTags().length == 0) {
    throw new AssertionError("@Option " + o.name() + " needs at least one OptionEffectTag");
  }
}

Prevention

When it happens

Trigger: Writing @Option(name = "x", defaultValue = "y") with no effectTags array; adding a new flag quickly and skipping annotation metadata.

Common situations: New flag development; copying an old pre-annotation-mandate declaration; refactoring options where effectTags were dropped during merges.

Related errors


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