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, where E is the type of an individual command-line mention of this option, but is of type %s

What it means

The third shape check for allowMultiple options in Bazel's options annotation processor: the declared List type must have exactly one type argument. Raw List (zero type arguments) or bizarre multi-arity declarations fail, because the processor needs the single element type E to determine the converter for each command-line mention of the option.

Source

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

      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,
            "Option that allows multiple occurrences must be of type %s, where E is the type of an"
                + " individual command-line mention of this option, but is of type %s",
            listType,
            optionType);
      }
      return ImmutableList.of(genericParameters.get(0), optionType);
    } else {
      return ImmutableList.of(optionType);
    }
  }

  private void checkForDefaultConverter(
      ExecutableElement method, List<TypeMirror> acceptedConverterReturnTypes, String defaultValue)
      throws OptionProcessorException {
    if (defaultConverters == null) {
      // Bootstrapping. Do not do this check.
      return;

View on GitHub (pinned to e6e199d060)

Solutions

  1. Parameterize the List with the per-occurrence value type: List<String>, List<Integer>, etc.
  2. Pick the element type to match an available converter (String, boolean, int, and other built-ins each have default converters).
  3. Recompile to confirm.

Example fix

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

Strategy: type-guard

Validate before calling

static void checkMultipleHasOneTypeArg(boolean allowMultiple,
                                        List<? extends TypeMirror> typeArgs) {
  if (allowMultiple) {
    Preconditions.checkState(typeArgs.size() == 1,
        "allowMultiple options must be List<E> with exactly one type argument");
  }
}

Type guard

static boolean isParameterizedList(java.lang.reflect.Type type) {
  return type instanceof ParameterizedType p
      && p.getRawType() == List.class
      && p.getActualTypeArguments().length == 1;
}

Prevention

When it happens

Trigger: @Option(allowMultiple = true) on a field of raw type List (no generic parameter), or a declared type whose getTypeArguments().size() != 1.

Common situations: Legacy or quick-and-dirty code using raw List; suppressing generics warnings; refactoring that accidentally drops the type parameter. Note the element type is then used to look up the converter, so leaving it raw makes converter resolution impossible.

Related errors


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