Context
httpx2 replaces a URL's query string whenever params are sent, including client-level params (pydantic/httpx2#905). httpware works around this in src/httpware/client.py: #145 (0.17.1) added the workaround, and #156 replaced it with _build_request, which strips the URL's query, lets httpx2 build the request, then puts the original query bytes back in front of the params. stream() goes through _stream / _stream_async for the same reason. Semantics match requests and pydantic/httpx2#966: params are appended after the URL's query, duplicate keys are kept, and the URL's query bytes are not re-encoded.
Blocked on
An httpx2 release that merges params into the existing URL query. Candidate fix: pydantic/httpx2#966 (open, unreviewed as of 2026-10-03). An earlier attempt, pydantic/httpx2#1026, was closed unmerged.
When unblocked
- Check upstream semantics still match ours: params appended after the URL query, duplicate keys kept, client params before per-request params,
params={} keeps the URL query, URL query bytes unchanged.
- Raise the
httpx2 floor in pyproject.toml to the release containing the fix.
- Replace every
_build_request(client, method, url, kwargs) call (build_request, _prepare_request and the capped stream helpers, in both worlds) with client.build_request(method, url, **kwargs), and delete _build_request. The uncapped stream() path can go back to self._httpx2_client.stream, dropping _stream / _stream_async.
- Keep
tests/test_url_query_merge.py: it passes 50/50 against #966 (2631c38) with the workaround stubbed out, so it should pass unchanged. If a case fails, upstream semantics differ from #966 and that is a behaviour change to call out in the release.
Context
httpx2 replaces a URL's query string whenever
paramsare sent, including client-level params (pydantic/httpx2#905). httpware works around this insrc/httpware/client.py: #145 (0.17.1) added the workaround, and #156 replaced it with_build_request, which strips the URL's query, lets httpx2 build the request, then puts the original query bytes back in front of the params.stream()goes through_stream/_stream_asyncfor the same reason. Semantics matchrequestsand pydantic/httpx2#966: params are appended after the URL's query, duplicate keys are kept, and the URL's query bytes are not re-encoded.Blocked on
An httpx2 release that merges
paramsinto the existing URL query. Candidate fix: pydantic/httpx2#966 (open, unreviewed as of 2026-10-03). An earlier attempt, pydantic/httpx2#1026, was closed unmerged.When unblocked
params={}keeps the URL query, URL query bytes unchanged.httpx2floor inpyproject.tomlto the release containing the fix._build_request(client, method, url, kwargs)call (build_request,_prepare_requestand the capped stream helpers, in both worlds) withclient.build_request(method, url, **kwargs), and delete_build_request. The uncappedstream()path can go back toself._httpx2_client.stream, dropping_stream/_stream_async.tests/test_url_query_merge.py: it passes 50/50 against #966 (2631c38) with the workaround stubbed out, so it should pass unchanged. If a case fails, upstream semantics differ from #966 and that is a behaviour change to call out in the release.