bazelbuild/bazel · error · OptionProcessorException
Option is an expansion flag with a static expansion, but doe
Error message
Option is an expansion flag with a static expansion, but does not have Void type.
What it means
Bazel's options annotation processor requires that an option with a static expansion (a non-empty expansion attribute) have return type Void. Expansion options exist purely to rewrite the command line; they carry no value of their own, so a non-Void return type signals a modeling mistake.
Source
Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:546
method, "Options with metadata tag DEPRECATED must be annotated with @Deprecated.");
}
if (hasDeprecatedAnnotation && !hasDeprecatedMetadataTag) {
throw new OptionProcessorException(
method, "Options annotated with @Deprecated must have metadata tag DEPRECATED.");
}
}
private void checkConverter(ExecutableElement method) throws OptionProcessorException {
TypeMirror optionType = method.getReturnType();
Option annotation = method.getAnnotation(Option.class);
ImmutableList<TypeMirror> acceptedConverterReturnTypes =
getAcceptedConverterReturnTypes(method);
// For simple, static expansions, don't accept non-Void types.
if (annotation.expansion().length != 0
&& !typeUtils.isSameType(
optionType, elementUtils.getTypeElement(Void.class.getCanonicalName()).asType())) {
throw new OptionProcessorException(
method,
"Option is an expansion flag with a static expansion, but does not have Void type.");
}
// Obtain the converter for this option.
AnnotationMirror optionMirror =
ProcessorUtils.getAnnotation(elementUtils, typeUtils, method, Option.class);
TypeElement defaultConverterElement =
elementUtils.getTypeElement(Converter.class.getCanonicalName());
TypeElement converterElement =
ProcessorUtils.getClassTypeFromAnnotationField(elementUtils, optionMirror, "converter");
if (typeUtils.isSameType(converterElement.asType(), defaultConverterElement.asType())) {
// Find a matching converter in the default converter list, and check that it successfully
// parses the default value for this option.
checkForDefaultConverter(method, acceptedConverterReturnTypes, annotation.defaultValue());
} else {
// Check that the provided converter has an accepted return type.View on GitHub (pinned to e6e199d060)
Solutions
- Change the option method's return type to Void (declared as void in the options class).
- If the option genuinely needs a value, remove the expansion attribute — a valued option cannot also be a static expansion.
- Recompile to confirm.
Example fix
// before
@Option(
name = "fast_build",
defaultValue = "false",
expansion = {"--compilation_mode=fastbuild"}
)
public static boolean fastBuild;
// after
@Option(
name = "fast_build",
defaultValue = "null",
expansion = {"--compilation_mode=fastbuild"}
)
public static void fastBuild; Defensive patterns
Strategy: type-guard
Validate before calling
static void checkExpansionIsVoid(String[] expansion, Class<?> optionType) {
if (expansion.length > 0) {
Preconditions.checkState(optionType == Void.class,
"Static expansion options must be Void, got %s", optionType);
}
} Type guard
// Ensure expansion options are declared Void before registration
static boolean isValidExpansionOption(String[] expansion, java.lang.reflect.Type type) {
return expansion.length == 0 || type == Void.class;
} Prevention
- Convention: every static expansion option is declared 'public static void' with defaultValue "null".
- Copy an existing, known-good expansion option as your template.
When it happens
Trigger: @Option(..., expansion = {"--foo=1"}) on a method whose return type is anything other than Void (e.g. Boolean, String, Integer) or void (primitive) — checked with Types.isSameType against java.lang.Void.
Common situations: Turning a valued flag into an alias for other flags while keeping its old type; writing a new expansion option by copying a Boolean-valued option; forgetting that expansion options are conventionally defined as 'public static void' accessor methods with Void in the abstract-option paradigm.
Related errors
- Can't set an option to be both an expansion option and have
- Can't set an option to accumulate multiple values and let it
- Option that allows multiple occurrences must be of type %s,
- Option that allows multiple occurrences must be assignable t
- Cannot find valid converter for option of type %s
AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14).
Data as JSON: /api/errors/1f132567c75a9f76.
Report an issue: GitHub.