bazelbuild/bazel · error · OptionProcessorException
Cannot find valid converter for option of type %s
Error message
Cannot find valid converter for option of type %s
What it means
After failing to match any registered default converter for the option's type (during default-value validation), Bazel's options annotation processor reports this error: no built-in converter exists for the option's return type. Options must either use a type with a known default converter or supply an explicit converter via the @Option converter attribute.
Source
Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:634
Converter<?> converterInstance = findDefaultConverter(acceptedConverterReturnType);
if (converterInstance == null) {
continue;
}
try {
converterInstance.convert(defaultValue, null);
} catch (OptionsParsingException e) {
TypeElement converter =
elementUtils.getTypeElement(converterInstance.getClass().getCanonicalName());
throw new OptionProcessorException(
method,
e,
"Option lists a default value (%s) that is not parsable by the option's converter (%s)",
defaultValue,
converter);
}
return;
}
throw new OptionProcessorException(
method,
"Cannot find valid converter for option of type %s",
acceptedConverterReturnTypes.get(0));
}
@Nullable
private Converter<?> findDefaultConverter(TypeMirror type) {
// According to the documentation of TypeMirror, equality check is not how one checks whether
// two instances reference the same type but Types.isSameType().
for (Map.Entry<TypeMirror, Converter<?>> entry : defaultConverters.entrySet()) {
if (typeUtils.isSameType(type, entry.getKey())) {
return entry.getValue();
}
}
return null;
}
private void checkProvidedConverter(View on GitHub (pinned to e6e199d060)
Solutions
- Write a class implementing Converter<MyType> (convert(String, Object) returning MyType) and reference it: @Option(..., converter = MyTypeConverter.class).
- Or change the option's type to one with a default converter (String, boolean, int, long, List<E> of those, etc.).
- If a suitable converter already exists in the codebase (search for 'implements Converter'), reuse it via the converter attribute rather than writing a new one.
- Recompile to confirm.
Example fix
// before @Option( name = "custom_timeout", defaultValue = "30s" ) public static DurationSpec customTimeout; // no default converter // after @Option( name = "custom_timeout", defaultValue = "30s", converter = DurationSpecConverter.class ) public static DurationSpec customTimeout;
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the option type has a default converter or an explicit one is supplied
static void assertConvertible(TypeMirror optionType,
Map<TypeMirror, Converter<?>> defaultConverters,
Class<? extends Converter<?>> explicitConverter) {
boolean hasDefault = defaultConverters.keySet().stream()
.anyMatch(t -> t.equals(optionType));
Preconditions.checkState(hasDefault || explicitConverter != null,
"No default converter for %s and no converter attribute set", optionType);
} Prevention
- Any option of a custom type must set converter = MyConverter.class in the same commit.
- Favor built-in types (String, boolean, int) when the option semantics allow it.
When it happens
Trigger: An @Option method whose return type has no entry in the processor's defaultConverters map and no explicit converter attribute — e.g. a custom class like MyCustomType, or a type whose only available converter is not registered with the processor.
Common situations: Adding options for domain types (paths, durations with custom formats, enums with special parsing) without writing a Converter; depending on a converter registered at runtime but unknown to the annotation processor; typos in generic element types after an allowMultiple refactor.
Related errors
- Type of field (%s) must be assignable from the converter's r
- 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/66c5d96e0cea5ac2.
Report an issue: GitHub.