Skip to content

Duplicate key class Parameter when documenting two GET methods with same path and PathVariable, differing only by produces media type. #3073

@ollio

Description

@ollio

When defining two @GetMapping handlers for the same path (e.g. /{organizationId}/features) and each has a unique operationId but shares the same @PathVariable organizationId, Springdoc fails with:

java.lang.IllegalStateException: Duplicate key class Parameter { name: "organizationId", ... }

Although both methods use distinct produces media types (application/json vs application/x-ndjson), Springdoc’s internal parameter processing merges duplicates improperly.

Steps to Reproduce:

  1. Define two GET methods in a @RestController with identical paths including {organizationId}, differing only in produces.
  2. Annotate each with unique @Operation(operationId = "...").
  3. Launch application and observe the exception due to duplicated parameter key.
  4. Add @operation doc with documentation of the param: parameters = {
    @parameter(name = "organizationId", in = ParameterIn.PATH
    }

Expected Behavior:
Springdoc should either:

  • Detect duplicate path parameters and include them only once in the OpenAPI spec, or
  • Merge the two operations into one GET with multiple content types, or
  • Cleanly support two operations on the same path when they differ only by response media type and have distinct operationIds.

Workaround:
I have removed the documentation of the parameter "organizationId".

Code example:

    @Operation(operationId = "getFeaturesJson", 
               parameters = {
                 @Parameter(name = "organizationId", in = ParameterIn.PATH
               })
    @GetMapping(value = "/{organizationId}/features", produces = MediaType.APPLICATION_JSON_VALUE)
    public List<Feature> getFeaturesAsJson(
        @PathVariable String organizationId) {
        return List.of(/* ... */);
    }

    @Operation(operationId = "getFeaturesNdjson",
              parameters = {
                 @Parameter(name = "organizationId", in = ParameterIn.PATH
              })
    @GetMapping(value = "/{organizationId}/features", produces = "application/x-ndjson")
    public Flux<Feature> getFeaturesAsNdjson(
        @PathVariable String organizationId) {
        return Flux.just(/* ... */);
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions