Skip to content

Bugfix to solve mixed correct and error response in produces annotation (#24948) - #24949

Open
AntoineDuComptoirDesPharmacies wants to merge 3 commits into
OpenAPITools:masterfrom
LeComptoirDesPharmacies:bugfix/24948
Open

AntoineDuComptoirDesPharmacies wants to merge 3 commits into
OpenAPITools:masterfrom
LeComptoirDesPharmacies:bugfix/24948

Conversation

@AntoineDuComptoirDesPharmacies

@AntoineDuComptoirDesPharmacies AntoineDuComptoirDesPharmacies commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #24948. Follow-up to #23935.

With splitOperationsByContentType=true, a variant generated for a non-JSON media-type (getReportAsCsv, typed on text/csv) still sent Accept: application/json whenever the operation also declared a JSON error response: produces is the union of every response's content, and every generator picks the Accept from that list with a rule that prefers JSON. Server generators had the mirror problem: two variants of the same route both declared application/json in produces, an ambiguous mapping.

A variant's produces is now the single media-type it was narrowed to, nothing else:

  • Core : fromOperation builds it from the method response alone, getProducesInfo returns the same media-type. Error responses keep their own content and typing.
  • Java : AbstractJavaCodegen stamps x-accepts / x-content-type on the variants as they are split (they were computed in preprocessOpenAPI, before the split). Computing them in fromOperation was tried and dropped: 48 samples changed, the extensions being exported into the serialized openapi.yaml.
  • rust-server-deprecated : usesXml set per XML response, as the maintained rust-server does.
  • Docs : global-properties.md updated.

Design note for reviewers: a Spring server variant declares only its own media-type in produces; that is what lets Spring route on Accept without an ambiguous mapping, and JSON error bodies still go through @ExceptionHandler, negotiated on the client's Accept. Opinions welcome.

  • Unsplit operations generate byte-identical output. Everything is behind the opt-in option.
  • Tests : New fixture with JSON error responses

PR checklist

  • [ X ] Read the contribution guidelines.
  • [ X ] Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • [ X ] If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@wing328

@cachescrubber (2022/02) @welshm (2022/02) @MelleD (2022/02) @atextor (2022/02) @manedev79 (2022/02) @javisst (2022/02) @borsch (2022/02) @banlevente (2022/02) @Zomzog (2022/09) @martin-mfg (2023/08) @KannaKim (2026/07)


Summary by cubic

Fixes #24948, a follow-up to #23935. With splitOperationsByContentType=true, a variant narrowed on the response axis still sent Accept: application/json when the operation also declared a JSON error response, because produces was the union of all response media types. Such variants now produce only the media type they were narrowed to; error responses keep their own content and typing. Variants split only on the request axis keep the operation's original produces, error responses included.

Java generators restamp x-accepts and x-content-type after the split, so each variant carries its own media types instead of inheriting the original operation's. rust-server-deprecated sets usesXml per XML response. Unsplit operations generate byte-identical output, since the fix is limited to the opt-in split path.

Written for commit d81a4f9. Summary will update on new commits.

Review in cubic

…pt to its own media-type

splitOperationsByContentType narrows a variant to one media-type on its success
response, but the other responses - errors, typically JSON - are left as they
are, so produces, the union of every response's content, still listed them all.
Every generator derives the Accept it sends from that list with a rule that
knows nothing about variants: the Java client and Python prefer JSON, Spring
Cloud's Feign contract takes the first one. On a spec with JSON errors the CSV
variant of a json|csv operation therefore asked for JSON, or the JSON one for
CSV - the very defect the split exists to remove, back through the Accept
header.

produces of a variant is now read from its method response alone, the one the
split narrowed, and getProducesInfo returns that single media-type; the error
responses are untouched and keep typing their body. Operations the split
leaves alone are unchanged: their produces is still the union of every
response. consumes needed nothing, the split already narrows the request body
it is read from.

The Java generators compute x-accepts and x-content-type themselves, in
preprocessOpenAPI, before the split: a variant inherited them from the
operation it came from. AbstractJavaCodegen now overrides
divideOperationsByContentType and stamps the variants it returns, each with its
own media-types; every other operation keeps the value preprocessOpenAPI
computed, which the Java generators also export in the openapi.yaml they
serialize. Computing the extensions in fromOperation alone was tried and
dropped: the export order changes and x-internal operations never reach it,
which touched 48 samples.

rust-server-deprecated flagged usesXml from the operation's produces, which no
longer lists an XML error response of a variant: the flag is set where the
response is tagged x-produces-xml, as the maintained rust-server does.

typescript-fetch needs nothing: it reads the media-types from the variant
extensions, and its split sample regenerates byte for byte. The docs state the
consequence for a server that negotiates strictly on Accept, and no longer
claim every generator sends the narrowed Accept (kotlin-client filters produces
down to what it can deserialise).
…e the extension names

contentTypeVariantMediaType checks the variant group itself: isContentTypeVariant
had no other caller. addContentTypeExtensions names x-accepts and x-content-type
through VendorExtension, as getSupportedVendorExtensions already does, and the
test helper reads the media-type key through the constant the class declares.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 9 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread docs/global-properties.md Outdated
A variant split on the request axis alone keeps the operation's produces, error
responses included, as any operation that was not split; the docs promised a
single media-type on both axes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][core] splitOperationsByContentType: a variant sends the Accept of another media-type when the operation has JSON error responses

1 participant