bazelbuild/bazel · error · OptionProcessorException

Option that allows multiple occurrences must be of type %s,

Error message

Option that allows multiple occurrences must be of type %s, but is of type %s

What it means

The first of three shape checks the Bazel options annotation processor runs on options with allowMultiple = true: the option's return (field) type must be a declared type (a class or interface such as List), not a primitive, array, or type variable. Repeatable options must accumulate values into a List-like declared type.

Source

Thrown at src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java:577

    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.
      checkProvidedConverter(method, acceptedConverterReturnTypes, converterElement);
    }
  }

  private ImmutableList<TypeMirror> getAcceptedConverterReturnTypes(ExecutableElement method)
      throws OptionProcessorException {
    TypeMirror optionType = method.getReturnType();
    Option annotation = method.getAnnotation(Option.class);
    TypeMirror listType = elementUtils.getTypeElement(List.class.getCanonicalName()).asType();

    if (annotation.allowMultiple()) {
      if (optionType.getKind() != TypeKind.DECLARED) {
        throw new OptionProcessorException(
            method,
            "Option that allows multiple occurrences must be of type %s, but is of type %s",
            listType,
            optionType);
      }
      DeclaredType optionDeclaredType = (DeclaredType) optionType;
      if (!typeUtils.isAssignable(typeUtils.erasure(optionDeclaredType), listType)) {
        throw new OptionProcessorException(
            method,
            "Option that allows multiple occurrences must be assignable to type %s, but is of type"
                + " %s",
            listType,
            optionType);
      }
      List<? extends TypeMirror> genericParameters = optionDeclaredType.getTypeArguments();
      if (genericParameters.size() != 1) {
        throw new OptionProcessorException(
            method,

View on GitHub (pinned to e6e199d060)

Solutions

  1. Change the option's type to List<E> (or a subtype), where E is the per-occurrence value type, e.g. List<String>.
  2. Ensure any generic base class resolves the option type to a concrete declared type; type variables never satisfy the check.
  3. Remember defaultValue must be "null" for allowMultiple options (separate check).
  4. Recompile to confirm.

Example fix

// before
@Option(
  name = "tag",
  defaultValue = "null",
  allowMultiple = true
)
public static String tag;
// after
@Option(
  name = "tag",
  defaultValue = "null",
  allowMultiple = true
)
public static List<String> tag;
Defensive patterns

Strategy: type-guard

Validate before calling

static void checkMultipleIsDeclaredType(boolean allowMultiple, TypeMirror t) {
  if (allowMultiple) {
    Preconditions.checkState(t.getKind() == TypeKind.DECLARED,
        "allowMultiple options must be a declared List type, got kind %s", t.getKind());
  }
}

Type guard

// Runtime/reflection analogue: repeatable options must be a class/interface type
static boolean isRepeatableOptionType(Class<?> clazz) {
  return !clazz.isPrimitive() && !clazz.isArray();
}

Prevention

When it happens

Trigger: @Option(allowMultiple = true) on a method whose type's TypeKind is not DECLARED — e.g. boolean, int, or a generic type variable T used in an abstract base options class.

Common situations: Switching a flag to allowMultiple without changing its primitive/simple type; genericizing an options base class so the option type becomes an unresolved type variable; arrays mistaken for an acceptable accumulation type.

Related errors


AI-assisted analysis of bazelbuild/bazel@e6e199d060 (2026-08-14). Data as JSON: /api/errors/966f5eec3a7e1377. Report an issue: GitHub.