`base_url` with a query string produces malformed request URLs

Open
#1,236 4 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@mohsinaliwork686-rgb is already working on this.

Since Oct 26, 2026.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
python
Domain
api, backend

Research direction

Start in _client.py by reading _enforce_trailing_slash and _merge_url, focusing on their use of raw_path when base_url contains a query. Reproduce both examples, then confirm with maintainers whether query-bearing base URLs should be rejected or supported; done means tests cover both relative requests and params= without malformed or missing paths.

Written by the indexing model from the issue text.

Description

A base_url that contains a query string is not rejected, but every relative request built from it has a broken URL. Reproduced on httpx2 2.13.1:

import httpx2

client = httpx2.Client(base_url="https://example.com/api?key=k")
print(repr(client.base_url))
# URL('https://example.com/api?key=k/')

print(client.build_request("GET", "items").url)
# https://example.com/api?key=k/items

print(client.build_request("GET", "items", params={"b": "2"}).url)
# https://example.com/api?b=2

In the first request the path ends up inside the query (key becomes k/items). In the second the path items is lost entirely. No error is raised in either case, so the request silently goes to the wrong URL.

Cause

Both steps operate on raw_path, which includes the query:

  • _enforce_trailing_slash (_client.py) appends / to url.raw_path, so the slash lands after the query: /api?key=k/.
  • _merge_url builds self.base_url.raw_path + merge_url.raw_path.lstrip(b"/"), so the request path is appended after the query too.

The second case then loses the path because params= replaces the whole query (#905), and the query now holds the path.

Possible fixes

  1. Reject a base_url with a query string in the base_url setter, with a message pointing to params=.
  2. Support it: operate on path rather than raw_path in both places and merge the base query into the request's params.
Dominant language
Python
Stars
1.6k
Forks
103
Avg merge
1d 19h
Merged PRs (30d)
25

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from pydantic/httpx2

All issues in pydantic/httpx2

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.