bazelbuild/bazel · error · OptionProcessorException
Options with metadata tag DEPRECATED must be annotated with
Error message
Options with metadata tag DEPRECATED must be annotated with @Deprecated.
What it means
Bazel's options annotation processor keeps the DEPRECATED metadata tag and the Java @Deprecated annotation in lockstep. This error fires when an @Option method declares OptionMetadataTag.DEPRECATED in metadataTags but is not annotated with java.lang.@Deprecated.
Source
Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:527
if (effectTags.contains(OptionEffectTag.NO_OP)
&& !metadataTags.contains(OptionMetadataTag.HIDDEN)
&& !metadataTags.contains(OptionMetadataTag.INTERNAL)
&& !hasDeprecatedAnnotation) {
// 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())) {View on GitHub (pinned to e6e199d060)
Solutions
- Add @Deprecated directly to the flagged @Option method (its paired check will then also pass).
- If the option is not actually deprecated, remove OptionMetadataTag.DEPRECATED from metadataTags instead.
- Recompile to confirm.
Example fix
// before
@Option(
name = "old_way",
defaultValue = "true",
effectTags = {OptionEffectTag.NO_OP},
metadataTags = {OptionMetadataTag.DEPRECATED}
)
// after
@Deprecated
@Option(
name = "old_way",
defaultValue = "true",
effectTags = {OptionEffectTag.NO_OP},
metadataTags = {OptionMetadataTag.DEPRECATED}
) Defensive patterns
Strategy: validation
Validate before calling
static void checkDeprecatedTagMatchesAnnotation(boolean hasDeprecatedTag,
boolean hasDeprecatedAnnotation) {
Preconditions.checkState(!hasDeprecatedTag || hasDeprecatedAnnotation,
"metadataTags DEPRECATED requires the @Deprecated annotation");
} Prevention
- Add @Deprecated and OptionMetadataTag.DEPRECATED as one atomic edit.
- Use a code template or IDE live template for deprecating options so both markers are always applied.
When it happens
Trigger: @Option(..., metadataTags = {OptionMetadataTag.DEPRECATED}) on a method without @Deprecated.
Common situations: Marking a flag deprecated in Bazel's generated documentation but forgetting the language-level annotation; copying an option definition that includes the tag; tooling or templates that add metadataTags automatically.
Related errors
- Options annotated with @Deprecated must have metadata tag DE
- Option includes NO_OP with other effects. This doesn't make
- Option has metadata tag %s but does not have category UNDOCU
- No-op options must be annotated with @Deprecated, or have me
- Option includes UNKNOWN with other, known, effects. Please r
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/088efdb05301f26b.
Report an issue: GitHub.