OpenAPITools/openapi-generator · error · IllegalArgumentException
Flags 'useSwaggerAnnotations' (v2) and 'useSwaggerV3Annotati
Error message
Flags 'useSwaggerAnnotations' (v2) and 'useSwaggerV3Annotations' (v3) are mutually exclusive. Please enable only one.
What it means
Thrown by JavaJAXRSSpecServerCodegen.processOpts when useSwaggerAnnotations (io.swagger v2 annotations) and useSwaggerV3Annotations (io.swagger.core.v3) are both true — the templates cannot emit both annotation sets. Note the code force-disables useSwaggerAnnotations when v3 is requested ('prefer v3'), so in the standard config-driven flow this guard is nearly unreachable; it exists to protect programmatic setter sequences and future option paths.
Source
Thrown at modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java:198
convertPropertyToBooleanAndWriteBack(SUPPORT_ASYNC, this::setSupportAsync);
if (QUARKUS_LIBRARY.equals(library) || THORNTAIL_LIBRARY.equals(library) || HELIDON_LIBRARY.equals(library) || OPEN_LIBERTY_LIBRARY.equals(library) || KUMULUZEE_LIBRARY.equals(library)) {
// disable Swagger v2 annotations in library modes; MicroProfile or Swagger v3 may be used instead
useSwaggerAnnotations = false;
} else {
convertPropertyToBooleanAndWriteBack(USE_SWAGGER_ANNOTATIONS, value -> useSwaggerAnnotations = value);
}
// Swagger v3 can be used regardless of library
convertPropertyToBooleanAndWriteBack(USE_SWAGGER_V3_ANNOTATIONS, value -> useSwaggerV3Annotations = value);
// prefer v3 when requested
if (useSwaggerV3Annotations) {
useSwaggerAnnotations = false;
}
if (KUMULUZEE_LIBRARY.equals(library)) {
super.setSourceFolder("src/main/java");
}
if (useSwaggerAnnotations && useSwaggerV3Annotations) {
throw new IllegalArgumentException("Flags 'useSwaggerAnnotations' (v2) and 'useSwaggerV3Annotations' (v3) are mutually exclusive. Please enable only one.");
}
if (useSwaggerV3Annotations && useMicroProfileOpenAPIAnnotations) {
throw new IllegalArgumentException("Flags 'useSwaggerV3Annotations' and 'useMicroProfileOpenAPIAnnotations' are mutually exclusive. Please enable only one.");
}
if (QUARKUS_LIBRARY.equals(library)) {
convertPropertyToBooleanAndWriteBack(USE_MICROPROFILE_OPENAPI_ANNOTATIONS, value -> useMicroProfileOpenAPIAnnotations = value);
}
if (QUARKUS_LIBRARY.equals(library)) {
convertPropertyToBooleanAndWriteBack(USE_MUTINY, value -> useMutiny = value);
}
convertPropertyToBooleanAndWriteBack(GENERATE_JSON_CREATOR, this::setGenerateJsonCreator);
convertPropertyToBooleanAndWriteBack(USE_ENUM_CASE_INSENSITIVE, this::setUseEnumCaseInsensitive);
convertPropertyToBooleanAndWriteBack(USE_SEALED, this::setUseSealed);
if (additionalProperties.containsKey(OPEN_API_SPEC_FILE_LOCATION)) {View on GitHub (pinned to fcec517be3)
Solutions
- Enable only one: keep useSwaggerV3Annotations=true and remove useSwaggerAnnotations (v3 is auto-preferred anyway)
- Audit merged config sources (CLI + --config file + configOptions) for both keys being set
- If you still target Swagger 2 tooling (springfox-era), keep useSwaggerAnnotations=true and drop the v3 flag
- In embedded usage, set the flags through additionalProperties rather than direct field/setter calls so the v3-preference logic runs
Example fix
# before openapi-generator-cli generate -g jaxrs-jersey -i api.yaml \ --additional-properties useSwaggerAnnotations=true,useSwaggerV3Annotations=true # after openapi-generator-cli generate -g jaxrs-jersey -i api.yaml \ --additional-properties useSwaggerV3Annotations=true
Defensive patterns
Strategy: validation
Validate before calling
boolean v2 = Boolean.parseBoolean(String.valueOf(opts.getOrDefault("useSwaggerAnnotations", "false")));
boolean v3 = Boolean.parseBoolean(String.valueOf(opts.getOrDefault("useSwaggerV3Annotations", "false")));
if (v2 && v3) {
throw new IllegalArgumentException("useSwaggerAnnotations and useSwaggerV3Annotations are mutually exclusive; keep only v3");
} Try / catch
try {
generator.generate();
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("mutually exclusive")) {
opts.remove("useSwaggerAnnotations"); // v3 is preferred by the generator
generator.generate();
} else throw e;
} Prevention
- Model annotation-version choices as a single 'swaggerVersion' input in your wrapper and expand to the exact one flag
- When upgrading Swagger 2 to v3, delete the old flag in the same change that adds the new one
- Diff merged option maps (base preset + override) before generation to catch resurrected flags
When it happens
Trigger: Passing --additional-properties useSwaggerAnnotations=true,useSwaggerV3Annotations=true to -g jaxrs-jersey (the JAX-RS spec generator). Programmatically setting both fields to true via setters after processOpts ordering differs. The CLI path alone normally cannot trip it because v3 wins first.
Common situations: Upgrades from Swagger 2 to OpenAPI 3 where teams enable the new flag but forget to remove the old one. Config management tools that merge option maps (base + override) can resurrect both flags even if the base config only meant one.
Related errors
- Flags 'useSwaggerV3Annotations' and 'useMicroProfileOpenAPIA
- Flag 'useJakartaSecurityAnnotations' requires 'useJakartaEe=
- You cannot combine [returnResponse] and [returnJBossResponse
- The [returnJBossResponse] requires [useJakartaEe] to be true
- useJackson3 is only supported for the 'native', 'apache-http
AI-assisted analysis of OpenAPITools/openapi-generator@fcec517be3 (2026-08-22).
Data as JSON: /api/errors/c6804d5813b594b6.
Report an issue: GitHub.