{"record":{"id":"a740cb7b333dedd0","repo":"bazelbuild/bazel","slug":"options-annotated-with-deprecated-must-have-metad","errorCode":null,"errorMessage":"Options annotated with @Deprecated must have metadata tag DEPRECATED.","messagePattern":"Options annotated with @Deprecated must have metadata tag DEPRECATED\\.","errorType":"validation","errorClass":"OptionProcessorException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java","lineNumber":531,"sourceCode":"      // Allowlist for tests - these are in the process of being fixed.\n      String enclosingClassName = method.getEnclosingElement().toString();\n      boolean allowlisted =\n          NO_OP_OPTION_ALLOWLIST.stream().anyMatch(enclosingClassName::startsWith);\n      if (!allowlisted) {\n        throw new OptionProcessorException(\n            method,\n            \"No-op options must be annotated with @Deprecated, or have metadata tag HIDDEN or\"\n                + \" INTERNAL. Alternatively add %s to the allowlist.\",\n            enclosingClassName);\n      }\n    }\n\n    if (hasDeprecatedMetadataTag && !hasDeprecatedAnnotation) {\n      throw new OptionProcessorException(\n          method, \"Options with metadata tag DEPRECATED must be annotated with @Deprecated.\");\n    }\n    if (hasDeprecatedAnnotation && !hasDeprecatedMetadataTag) {\n      throw new OptionProcessorException(\n          method, \"Options annotated with @Deprecated must have metadata tag DEPRECATED.\");\n    }\n  }\n\n  private void checkConverter(ExecutableElement method) throws OptionProcessorException {\n    TypeMirror optionType = method.getReturnType();\n    Option annotation = method.getAnnotation(Option.class);\n    ImmutableList<TypeMirror> acceptedConverterReturnTypes =\n        getAcceptedConverterReturnTypes(method);\n\n    // For simple, static expansions, don't accept non-Void types.\n    if (annotation.expansion().length != 0\n        && !typeUtils.isSameType(\n            optionType, elementUtils.getTypeElement(Void.class.getCanonicalName()).asType())) {\n      throw new OptionProcessorException(\n          method,\n          \"Option is an expansion flag with a static expansion, but does not have Void type.\");\n    }","sourceCodeStart":513,"sourceCodeEnd":549,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java#L513-L549","documentation":"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.","triggerScenarios":"A method carrying both @Option and @Deprecated whose metadataTags attribute does not include OptionMetadataTag.DEPRECATED.","commonSituations":"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).","solutions":["Add OptionMetadataTag.DEPRECATED to the method's metadataTags array.","If the deprecation itself was accidental, remove @Deprecated from the method instead.","Recompile to confirm."],"exampleFix":"// before\n@Deprecated\n@Option(\n  name = \"legacy_path\",\n  defaultValue = \"null\",\n  effectTags = {OptionEffectTag.EAGER}\n)\n// after\n@Deprecated\n@Option(\n  name = \"legacy_path\",\n  defaultValue = \"null\",\n  effectTags = {OptionEffectTag.EAGER},\n  metadataTags = {OptionMetadataTag.DEPRECATED}\n)","handlingStrategy":"validation","validationCode":"static void checkAnnotationMatchesDeprecatedTag(boolean hasDeprecatedAnnotation,\n                                                     boolean hasDeprecatedTag) {\n  Preconditions.checkState(!hasDeprecatedAnnotation || hasDeprecatedTag,\n      \"@Deprecated options must add metadataTags DEPRECATED\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never apply a bare @Deprecated to an @Option method; always include the DEPRECATED metadata tag.","When deprecating whole options classes, check each @Option method individually."],"tags":["java","bazel","annotation-processing","options","compile-time","deprecation","option-metadata-tags"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}