bazelbuild/bazel · error · OptionProcessorException
The converter type %s must be a concrete type
Error message
The converter type %s must be a concrete type
What it means
When an @Option specifies a custom converter class, Bazel's options annotation processor verifies the converter is instantiable. This error fires when the supplied converter class is abstract: the processor cannot instantiate it to call convert(), so the option definition is rejected at compile time.
Source
Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:658
@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(
ExecutableElement method,
ImmutableList<TypeMirror> acceptedConverterReturnTypes,
TypeElement converterElement)
throws OptionProcessorException {
if (converterElement.getModifiers().contains(Modifier.ABSTRACT)) {
throw new OptionProcessorException(
method, "The converter type %s must be a concrete type", converterElement.asType());
}
DeclaredType converterType = (DeclaredType) converterElement.asType();
List<ExecutableElement> methodList =
elementUtils.getAllMembers(converterElement).stream()
.filter(element -> element.getKind() == ElementKind.METHOD)
.map(methodElement -> (ExecutableElement) methodElement)
.filter(methodElement -> methodElement.getSimpleName().contentEquals("convert"))
.filter(
methodElement ->
methodElement.getParameters().size() == 2
&& typeUtils.isSameType(
methodElement.getParameters().get(0).asType(),
elementUtils.getTypeElement(String.class.getCanonicalName()).asType())
&& typeUtils.isSameType(
methodElement.getParameters().get(1).asType(),
elementUtils.getTypeElement(Object.class.getCanonicalName()).asType()))View on GitHub (pinned to e6e199d060)
Solutions
- Reference the concrete subclass in the converter attribute: converter = ConcreteConverter.class.
- If the abstract class is the only thing that exists, implement it as a concrete class (or make it a final utility class implementing Converter directly).
- Recompile to confirm.
Example fix
// before
abstract class TimeoutConverter implements Converter<Duration> { ... }
@Option(
name = "timeout",
defaultValue = "30s",
converter = TimeoutConverter.class // abstract -> error
)
// after
final class TimeoutConverter implements Converter<Duration> { ... }
@Option(
name = "timeout",
defaultValue = "30s",
converter = TimeoutConverter.class
) Defensive patterns
Strategy: type-guard
Validate before calling
static void assertConverterConcrete(Class<? extends Converter<?>> converter) {
Preconditions.checkState(!Modifier.isAbstract(converter.getModifiers()),
"Converter %s must be concrete (non-abstract)", converter.getName());
} Type guard
static boolean isInstantiableConverter(Class<?> c) {
return Converter.class.isAssignableFrom(c)
&& !c.isInterface()
&& !Modifier.isAbstract(c.getModifiers());
} Prevention
- Make converter classes final and concrete; avoid abstract converter bases referenced from @Option.
- When introducing a converter hierarchy, update every @Option converter reference to the leaf class.
When it happens
Trigger: @Option(..., converter = SomeAbstractConverter.class) where SomeAbstractConverter is declared abstract (or is an interface referenced as a converter).
Common situations: Pointing at a converter base class instead of a concrete subclass; introducing a generic converter hierarchy and wiring the base type by mistake; refactoring a converter into abstract+concrete pair and forgetting to update the @Option reference.
Related errors
- Option lists a default value (%s) that is not parsable by th
- Cannot find valid converter for option of type %s
- Converter %s has %d methods 'convert(String, Object)', expec
- Type of field (%s) must be assignable from the converter's r
- Option includes UNKNOWN with other, known, effects. Please r
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/08ed59cb5061ed75.
Report an issue: GitHub.