{"record":{"id":"6128753b0f5ffa40","repo":"bazelbuild/bazel","slug":"option-method-must-be-abstract","errorCode":null,"errorMessage":"@Option method must be abstract","messagePattern":"@Option method must be abstract","errorType":"validation","errorClass":"OptionProcessorException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java","lineNumber":332,"sourceCode":"              option.capitalizedFieldName,\n              option.hasSetterInBase ? \"@Override\" : \"\");\n        }\n\n        out.println(\"}\");\n      }\n    } catch (IOException e) {\n      messager.printMessage(\n          Diagnostic.Kind.ERROR,\n          \"Failed to generate implementation for \" + className + \": \" + e.getMessage());\n    }\n  }\n\n  private void checkMethodOption(ExecutableElement method) throws OptionProcessorException {\n    if (!method.getModifiers().contains(Modifier.PUBLIC)) {\n      throw new OptionProcessorException(method, \"@Option method must be public\");\n    }\n    if (!method.getModifiers().contains(Modifier.ABSTRACT)) {\n      throw new OptionProcessorException(method, \"@Option method must be abstract\");\n    }\n\n    String methodName = method.getSimpleName().toString();\n    if (!methodName.startsWith(\"get\")\n        || methodName.length() < 4\n        || !Character.isUpperCase(methodName.charAt(3))) {\n      throw new OptionProcessorException(\n          method, \"Annotated method name must start with 'get' followed by an uppercase letter\");\n    }\n\n    checkOptionName(method);\n    checkOldCategoriesAreNotUsed(method);\n    checkExpansionOptions(method);\n    checkConverter(method);\n    checkEffectTagRationality(method);\n    checkMetadataTagAndCategoryRationality(method);\n    checkNoDefaultValueForMultipleOption(method);\n    checkDeprecated(method);","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java#L314-L350","documentation":"The options annotation processor requires @Option-annotated interface methods to be abstract — no default bodies — because the processor generates the implementation itself. A method with a default implementation (or otherwise non-abstract) fails this check at compile time immediately after the visibility check.","triggerScenarios":"Giving an @Option interface method a default body: `default String getFoo() { return \"x\"; }`, or converting an existing interface where the getter already has a default.","commonSituations":"Refactoring old option classes where defaults lived in getters; IDE 'extract interface' producing default methods; copy-pasting a concrete getter into a new options interface.","solutions":["Remove the method body and the default keyword, leaving only the signature","Express the default via @Option(defaultValue = ...) on the annotation instead","Recompile to confirm the processor accepts the interface"],"exampleFix":"// before\n@Option(name = \"foo\", defaultValue = \"x\", effectTags = {OptionEffectTag.NO_OP})\ndefault String getFoo() { return \"x\"; }\n// after\n@Option(name = \"foo\", defaultValue = \"x\", effectTags = {OptionEffectTag.NO_OP})\nString getFoo();","handlingStrategy":"validation","validationCode":"// Fail tests that find default bodies on @Option methods\nfor (var m : MyOptions.class.getMethods()) {\n  if (m.isAnnotationPresent(Option.class) && !Modifier.isAbstract(m.getModifiers())) {\n    throw new AssertionError(\"@Option method must be abstract: \" + m);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Put defaults in @Option(defaultValue = ...), never in method bodies","Avoid IDE 'extract interface' refactors on option classes without reviewing generated defaults"],"tags":["bazel","options","annotation-processor","compile-time","java"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}