{"record":{"id":"b7bcadccf9d57447","repo":"bazelbuild/bazel","slug":"type-of-field-s-must-be-assignable-from-the-con","errorCode":null,"errorMessage":"Type of field (%s) must be assignable from the converter's return type (%s)","messagePattern":"Type of field \\((.+?)\\) must be assignable from the converter's return type \\((.+?)\\)","errorType":"validation","errorClass":"OptionProcessorException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java","lineNumber":696,"sourceCode":"\n    if (methodList.size() != 1) {\n      throw new OptionProcessorException(\n          method,\n          \"Converter %s has %d methods 'convert(String, Object)', expected 1: %s\",\n          converterElement,\n          methodList.size(),\n          methodList.stream().map(Object::toString).collect(Collectors.joining(\", \")));\n    }\n\n    ExecutableType convertMethodType =\n        (ExecutableType) typeUtils.asMemberOf(converterType, methodList.get(0));\n    TypeMirror convertMethodResultType = convertMethodType.getReturnType();\n    for (TypeMirror acceptedConverterReturnType : acceptedConverterReturnTypes) {\n      if (typeUtils.isAssignable(convertMethodResultType, acceptedConverterReturnType)) {\n        return;\n      }\n    }\n    throw new OptionProcessorException(\n        method,\n        \"Type of field (%s) must be assignable from the converter's return type (%s)\",\n        acceptedConverterReturnTypes.get(0),\n        convertMethodResultType);\n  }\n}\n","sourceCodeStart":678,"sourceCodeEnd":703,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java#L678-L703","documentation":"The final converter check in Bazel's options annotation processor: the return type of the converter's convert method must be assignable to the option's declared type (or, for allowMultiple options, to the List's element type). If convert() returns something the option field cannot hold, the option definition is rejected at compile time.","triggerScenarios":"@Option on a field of type T with converter = C.class where C.convert(...) returns a type not assignable to T — e.g. field is Integer but converter returns Long; field is List<String> (allowMultiple) but the converter returns Object; converter generic raw type erasing to a supertype of the field type.","commonSituations":"Reusing a converter whose output type is 'close but not assignable' (Long vs Integer, Object vs String); raw-typed converters losing generic info so the resolved return type is Object; changing an option's field type without updating the converter reference.","solutions":["Switch to (or write) a converter whose convert return type matches the option field type exactly, e.g. Converter<Integer> for an int option.","Or change the option's field type to match what the chosen converter produces.","For allowMultiple options, remember the converter target is the List's element type E, not the List itself.","Recompile to confirm."],"exampleFix":"// before\n@Option(\n  name = \"retries\",\n  defaultValue = \"3\",\n  converter = LongConverter.class  // returns Long\n)\npublic static int retries;  // int not assignable from Long\n// after\n@Option(\n  name = \"retries\",\n  defaultValue = \"3\",\n  converter = IntegerConverter.class  // returns Integer\n)\npublic static int retries;","handlingStrategy":"type-guard","validationCode":"static void assertConverterReturnTypeAssignable(Class<?> optionType,\n                                                     Class<? extends Converter<?>> converter) {\n  Class<?> returned = converter.getMethod(\"convert\", String.class, Object.class).getReturnType();\n  Preconditions.checkState(optionType.isAssignableFrom(returned),\n      \"Converter returns %s which is not assignable to option type %s\",\n      returned, optionType);\n}","typeGuard":"static boolean converterMatchesOption(Class<? extends Converter<?>> converter,\n                                        Class<?> optionType) throws Exception {\n  Class<?> r = converter.getMethod(\"convert\", String.class, Object.class).getReturnType();\n  return optionType.isAssignableFrom(r);\n}","tryCatchPattern":null,"preventionTips":["Match converter generic parameter and field type exactly (Integer converter for int/Integer fields).","For allowMultiple options, the converter converts the element type E of the List, not the List itself.","Avoid raw-typed converters; parameterize them so return types resolve precisely."],"tags":["java","bazel","annotation-processing","options","compile-time","converter","type-checking","assignability"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}