bazelbuild/bazel · error · OptionProcessorException
Type of field (%s) must be assignable from the converter's r
Error message
Type of field (%s) must be assignable from the converter's return type (%s)
What it means
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.
Source
Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:696
if (methodList.size() != 1) {
throw new OptionProcessorException(
method,
"Converter %s has %d methods 'convert(String, Object)', expected 1: %s",
converterElement,
methodList.size(),
methodList.stream().map(Object::toString).collect(Collectors.joining(", ")));
}
ExecutableType convertMethodType =
(ExecutableType) typeUtils.asMemberOf(converterType, methodList.get(0));
TypeMirror convertMethodResultType = convertMethodType.getReturnType();
for (TypeMirror acceptedConverterReturnType : acceptedConverterReturnTypes) {
if (typeUtils.isAssignable(convertMethodResultType, acceptedConverterReturnType)) {
return;
}
}
throw new OptionProcessorException(
method,
"Type of field (%s) must be assignable from the converter's return type (%s)",
acceptedConverterReturnTypes.get(0),
convertMethodResultType);
}
}
View on GitHub (pinned to e6e199d060)
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.
Example fix
// before @Option( name = "retries", defaultValue = "3", converter = LongConverter.class // returns Long ) public static int retries; // int not assignable from Long // after @Option( name = "retries", defaultValue = "3", converter = IntegerConverter.class // returns Integer ) public static int retries;
Defensive patterns
Strategy: type-guard
Validate before calling
static void assertConverterReturnTypeAssignable(Class<?> optionType,
Class<? extends Converter<?>> converter) {
Class<?> returned = converter.getMethod("convert", String.class, Object.class).getReturnType();
Preconditions.checkState(optionType.isAssignableFrom(returned),
"Converter returns %s which is not assignable to option type %s",
returned, optionType);
} Type guard
static boolean converterMatchesOption(Class<? extends Converter<?>> converter,
Class<?> optionType) throws Exception {
Class<?> r = converter.getMethod("convert", String.class, Object.class).getReturnType();
return optionType.isAssignableFrom(r);
} Prevention
- 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.
When it happens
Trigger: @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.
Common situations: 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.
Related errors
- Cannot find valid converter for option of type %s
- Option is an expansion flag with a static expansion, but doe
- Option that allows multiple occurrences must be of type %s,
- Option that allows multiple occurrences must be assignable t
- Option lists a default value (%s) that is not parsable by th
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/b7bcadccf9d57447.
Report an issue: GitHub.