bazelbuild/bazel · error · OptionProcessorException

Options annotated with @Deprecated must have metadata tag DE

Error message

Options annotated with @Deprecated must have metadata tag DEPRECATED.

What it means

The mirror of the previous check in Bazel's options annotation processor: an @Option method annotated with java.lang.@Deprecated must also declare OptionMetadataTag.DEPRECATED in metadataTags, so that Bazel's generated documentation marks the flag as deprecated consistently with the Java API.

Source

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

      // Allowlist for tests - these are in the process of being fixed.
      String enclosingClassName = method.getEnclosingElement().toString();
      boolean allowlisted =
          NO_OP_OPTION_ALLOWLIST.stream().anyMatch(enclosingClassName::startsWith);
      if (!allowlisted) {
        throw new OptionProcessorException(
            method,
            "No-op options must be annotated with @Deprecated, or have metadata tag HIDDEN or"
                + " INTERNAL. Alternatively add %s to the allowlist.",
            enclosingClassName);
      }
    }

    if (hasDeprecatedMetadataTag && !hasDeprecatedAnnotation) {
      throw new OptionProcessorException(
          method, "Options with metadata tag DEPRECATED must be annotated with @Deprecated.");
    }
    if (hasDeprecatedAnnotation && !hasDeprecatedMetadataTag) {
      throw new OptionProcessorException(
          method, "Options annotated with @Deprecated must have metadata tag DEPRECATED.");
    }
  }

  private void checkConverter(ExecutableElement method) throws OptionProcessorException {
    TypeMirror optionType = method.getReturnType();
    Option annotation = method.getAnnotation(Option.class);
    ImmutableList<TypeMirror> acceptedConverterReturnTypes =
        getAcceptedConverterReturnTypes(method);

    // For simple, static expansions, don't accept non-Void types.
    if (annotation.expansion().length != 0
        && !typeUtils.isSameType(
            optionType, elementUtils.getTypeElement(Void.class.getCanonicalName()).asType())) {
      throw new OptionProcessorException(
          method,
          "Option is an expansion flag with a static expansion, but does not have Void type.");
    }

View on GitHub (pinned to e6e199d060)

Solutions

  1. Add OptionMetadataTag.DEPRECATED to the method's metadataTags array.
  2. If the deprecation itself was accidental, remove @Deprecated from the method instead.
  3. Recompile to confirm.

Example fix

// before
@Deprecated
@Option(
  name = "legacy_path",
  defaultValue = "null",
  effectTags = {OptionEffectTag.EAGER}
)
// after
@Deprecated
@Option(
  name = "legacy_path",
  defaultValue = "null",
  effectTags = {OptionEffectTag.EAGER},
  metadataTags = {OptionMetadataTag.DEPRECATED}
)
Defensive patterns

Strategy: validation

Validate before calling

static void checkAnnotationMatchesDeprecatedTag(boolean hasDeprecatedAnnotation,
                                                     boolean hasDeprecatedTag) {
  Preconditions.checkState(!hasDeprecatedAnnotation || hasDeprecatedTag,
      "@Deprecated options must add metadataTags DEPRECATED");
}

Prevention

When it happens

Trigger: A method carrying both @Option and @Deprecated whose metadataTags attribute does not include OptionMetadataTag.DEPRECATED.

Common situations: Applying @Deprecated to an options class or method during ordinary Java cleanup without updating the @Option metadata; deprecating an option for removal but wanting it to stay documented (the tag, not category, is how deprecation is expressed now).

Related errors


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