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

  1. Enable only one: keep useSwaggerV3Annotations=true and remove useSwaggerAnnotations (v3 is auto-preferred anyway)
  2. Audit merged config sources (CLI + --config file + configOptions) for both keys being set
  3. If you still target Swagger 2 tooling (springfox-era), keep useSwaggerAnnotations=true and drop the v3 flag
  4. 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

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


AI-assisted analysis of OpenAPITools/openapi-generator@fcec517be3 (2026-08-22). Data as JSON: /api/errors/c6804d5813b594b6. Report an issue: GitHub.