{"record":{"id":"430c8680e3451656","repo":"bazelbuild/bazel","slug":"options-that-are-used-on-the-command-line-as-flags","errorCode":null,"errorMessage":"Options that are used on the command line as flags must have names made from word characters only.","messagePattern":"Options that are used on the command line as flags must have names made from word characters only\\.","errorType":"validation","errorClass":"OptionProcessorException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java","lineNumber":364,"sourceCode":"    checkConverter(method);\n    checkEffectTagRationality(method);\n    checkMetadataTagAndCategoryRationality(method);\n    checkNoDefaultValueForMultipleOption(method);\n    checkDeprecated(method);\n  }\n\n  private void checkOptionName(ExecutableElement method) throws OptionProcessorException {\n    Option annotation = method.getAnnotation(Option.class);\n    String optionName = annotation.name();\n    if (optionName.isEmpty()) {\n      throw new OptionProcessorException(method, \"Option must have an actual name.\");\n    }\n\n    if (!ImmutableList.copyOf(annotation.metadataTags()).contains(OptionMetadataTag.INTERNAL)) {\n      if (!Pattern.matches(\"([\\\\w:-])*\", optionName)) {\n        // Ideally, this would be just \\w, but - and : are needed for legacy options. We can lie in\n        // the error though, no harm in encouraging good behavior.\n        throw new OptionProcessorException(\n            method,\n            \"Options that are used on the command line as flags must have names made from word \"\n                + \"characters only.\");\n      }\n    }\n  }\n\n  private void checkEffectTagRationality(ExecutableElement method) throws OptionProcessorException {\n    Option annotation = method.getAnnotation(Option.class);\n    OptionEffectTag[] effectTags = annotation.effectTags();\n    if (effectTags.length < 1) {\n      throw new OptionProcessorException(\n          method,\n          \"Option does not list at least one OptionEffectTag. If the option has no effect, \"\n              + \"please be explicit and add NO_OP. Otherwise, add a tag representing its effect.\");\n    } else if (effectTags.length > 1) {\n      // If there are more than 1 tag, make sure that NO_OP and UNKNOWN is not one of them.\n      // These don't make sense if other effects are listed.","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java#L346-L382","documentation":"Flag names are used verbatim on the command line, so (unless the option is tagged OptionMetadataTag.INTERNAL) the processor validates the name against the pattern [\\w:-]* — word characters plus, as legacy tolerance, '-' and ':'. Any other character (space, '=', '.', '/', '#', etc.) is rejected with this message, which deliberately overstates the restriction to push toward clean names.","triggerScenarios":"Declaring @Option(name = \"foo.bar\"), \"my flag\", \"foo=value\", or any name with non-[\\w:-] characters and not marking it INTERNAL.","commonSituations":"Wanting dotted or namespaced flag names; pasting names from external tooling with spaces or unicode; forgetting that '=' in a name would make '--name=value' ambiguous.","solutions":["Rewrite the name using only letters, digits, underscore, and (if legacy-needed) '-' or ':'","If a weird name is genuinely required and never user-facing, add metadataTags = {OptionMetadataTag.INTERNAL}","Prefer snake_case word characters for new flags since '-' and ':' are legacy allowances"],"exampleFix":"// before\n@Option(name = \"foo.bar\", effectTags = {OptionEffectTag.NO_OP})\nString getFooBar();\n// after\n@Option(name = \"foo_bar\", effectTags = {OptionEffectTag.NO_OP})\nString getFooBar();","handlingStrategy":"validation","validationCode":"// Validate the option name charset ([\\w:-]*) outside the processor\nvar OK = java.util.regex.Pattern.compile(\"[\\\\w:-]*\");\nfor (var m : MyOptions.class.getMethods()) {\n  Option o = m.getAnnotation(Option.class);\n  if (o != null && !o.name().isEmpty() && !OK.matcher(o.name()).matches()\n      && !java.util.List.of(o.metadataTags()).contains(OptionMetadataTag.INTERNAL)) {\n    throw new AssertionError(\"Illegal option name: \" + o.name());\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use snake_case word characters for new flag names","Reserve '-' and ':' spellings for legacy options only","Tag genuinely internal options with OptionMetadataTag.INTERNAL"],"tags":["bazel","options","annotation-processor","compile-time","naming-convention","java"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}