Repository navigation
fix: Let httpx2 choose the multipart/form-data boundary - #1511
Merged
dbanty merged 1 commit intoNov 7, 2026
Merged
Conversation
Generated endpoints set Content-Type to multipart/form-data with the fixed boundary +++, so a file containing "\r\n--+++" was split at that point. Leave Content-Type unset for multipart bodies and let httpx2 add it with a random boundary, which also covers endpoints with several body types (openapi-generators#947). Fixes openapi-generators#1509
Merged
sda-mikerochefort
pushed a commit
to sda-mikerochefort/openapi-python-client
that referenced
this pull request
Nov 7, 2026
> [!IMPORTANT] > Merging this pull request will create this release ## ❗️Breaking ❗ ### Switch from `httpx` to `httpx2` in generated clients [`httpx2`](https://pydantic.dev/docs/httpx2/get-started/) is largely compatible with `httpx` and should only be a breaking change for users who customize the internal `Client`. Thanks to @s-sajid-ali and @johnthagen for making this one happen in PR openapi-generators#1461 and discussion openapi-generators#1455! ## 🚀 Features - Update `uv_build` to 0.13 when using `--meta=uv` (openapi-generators#1507) ## 🐛 Fixes - Let httpx2 choose the multipart/form-data boundary (openapi-generators#1511) ### Let httpx2 choose the boundary for `multipart/form-data` requests Since 0.29.0, generated endpoints sent every `multipart/form-data` body with the fixed boundary `+++`, so an uploaded file containing `\r\n--+++` was cut short at that point (openapi-generators#1509). These bodies no longer set `Content-Type`, so httpx2 sets it with a random boundary for each request, as single-body endpoints did before 0.29.0. Endpoints with several body types still get a boundary (openapi-generators#947). Co-authored-by: knope-bot[bot] <152252888+knope-bot[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1509
Since #1005 every generated
multipart/form-datarequest setsContent-Type: multipart/form-data; boundary=+++. httpx2 builds the body with that boundary, so a file that contains\r\n--+++is split there and the server gets a truncated file plus a stray part.This stops setting
Content-Typeformultipart/form-databodies. httpx2 then adds the header with its own random boundary, the same way single-body endpoints worked before 0.29.0. For endpoints with several body types, the multipart branch no longer sets the header either, so #947 stays fixed: httpx2 still writes a boundary because the header isn't set. The other content types still set their header explicitly.Changes:
endpoint_module.py.jinja: skip theContent-Typeline for multipart bodies.boundary=+++line goes away).test_multipart_bodies.py: generates a single-body and a multi-body endpoint, sends a file containing\r\n--+++through aMockTransportand parses the multipart body back.Testing:
pytest end_to_end_tests/functional_tests/generated_code_execution/test_multipart_bodies.py{'file': b'first line'} != {'file': b'first line\r\n--+++\r\nstill the same file\r\n'}), 1 passed (JSON control)pdm testequivalent with coverage: 471 passed, 100% coverage, 5 snapshots passedruff format --check .,ruff check .,mypy openapi_python_client fuzzpassI didn't run the
integrationjob locally because it needs the openapi-test-server container.