{"record":{"id":"966f5eec3a7e1377","repo":"bazelbuild/bazel","slug":"option-that-allows-multiple-occurrences-must-be-of","errorCode":null,"errorMessage":"Option that allows multiple occurrences must be of type %s, but is of type %s","messagePattern":"Option that allows multiple occurrences must be of type (.+?), but is of type (.+?)","errorType":"validation","errorClass":"OptionProcessorException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java","lineNumber":577,"sourceCode":"    if (typeUtils.isSameType(converterElement.asType(), defaultConverterElement.asType())) {\n      // Find a matching converter in the default converter list, and check that it successfully\n      // parses the default value for this option.\n      checkForDefaultConverter(method, acceptedConverterReturnTypes, annotation.defaultValue());\n    } else {\n      // Check that the provided converter has an accepted return type.\n      checkProvidedConverter(method, acceptedConverterReturnTypes, converterElement);\n    }\n  }\n\n  private ImmutableList<TypeMirror> getAcceptedConverterReturnTypes(ExecutableElement method)\n      throws OptionProcessorException {\n    TypeMirror optionType = method.getReturnType();\n    Option annotation = method.getAnnotation(Option.class);\n    TypeMirror listType = elementUtils.getTypeElement(List.class.getCanonicalName()).asType();\n\n    if (annotation.allowMultiple()) {\n      if (optionType.getKind() != TypeKind.DECLARED) {\n        throw new OptionProcessorException(\n            method,\n            \"Option that allows multiple occurrences must be of type %s, but is of type %s\",\n            listType,\n            optionType);\n      }\n      DeclaredType optionDeclaredType = (DeclaredType) optionType;\n      if (!typeUtils.isAssignable(typeUtils.erasure(optionDeclaredType), listType)) {\n        throw new OptionProcessorException(\n            method,\n            \"Option that allows multiple occurrences must be assignable to type %s, but is of type\"\n                + \" %s\",\n            listType,\n            optionType);\n      }\n      List<? extends TypeMirror> genericParameters = optionDeclaredType.getTypeArguments();\n      if (genericParameters.size() != 1) {\n        throw new OptionProcessorException(\n            method,","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/bazelbuild/bazel/blob/e6e199d0601a244511b4cf18c8b2828aa73db1fd/src/main/java/com/google/devtools/common/options/processor/OptionsClassProcessor.java#L559-L595","documentation":"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.","triggerScenarios":"@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.","commonSituations":"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.","solutions":["Change the option's type to List<E> (or a subtype), where E is the per-occurrence value type, e.g. List<String>.","Ensure any generic base class resolves the option type to a concrete declared type; type variables never satisfy the check.","Remember defaultValue must be \"null\" for allowMultiple options (separate check).","Recompile to confirm."],"exampleFix":"// before\n@Option(\n  name = \"tag\",\n  defaultValue = \"null\",\n  allowMultiple = true\n)\npublic static String tag;\n// after\n@Option(\n  name = \"tag\",\n  defaultValue = \"null\",\n  allowMultiple = true\n)\npublic static List<String> tag;","handlingStrategy":"type-guard","validationCode":"static void checkMultipleIsDeclaredType(boolean allowMultiple, TypeMirror t) {\n  if (allowMultiple) {\n    Preconditions.checkState(t.getKind() == TypeKind.DECLARED,\n        \"allowMultiple options must be a declared List type, got kind %s\", t.getKind());\n  }\n}","typeGuard":"// Runtime/reflection analogue: repeatable options must be a class/interface type\nstatic boolean isRepeatableOptionType(Class<?> clazz) {\n  return !clazz.isPrimitive() && !clazz.isArray();\n}","tryCatchPattern":null,"preventionTips":["Always declare allowMultiple options as List<E> — primitives, arrays, and type variables are never valid.","In generic base option classes, bind the option type to a concrete List<E> in subclasses."],"tags":["java","bazel","annotation-processing","options","compile-time","allow-multiple","type-checking"],"backgroundTag":null,"analyzedSha":"e6e199d0601a244511b4cf18c8b2828aa73db1fd","analyzedAt":"2026-08-14T10:24:27.848Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}