Fixing unexpected keyword argument 'proxies' in httpx
httpx 0.28 removed one argument. Downgrading works, but the replacement is two lines, and it does more than the old one did.
In short
Replace proxies=url with proxy=url. Replace a proxies={…} dictionary with mounts= and one HTTPTransport(proxy=…) per key. If the error comes from a library, such as an older OpenAI SDK, update the library.
httpx now has proxy=, a single proxy for every request, and mounts= for the per-scheme case. 0.27 already had both and kept proxies= working with a DeprecationWarning. 0.28 removed it. We ran the same calls on both versions:
| Call | httpx 0.27.2 | httpx 0.28.1 |
|---|---|---|
| httpx.Client(proxies=url) | works, DeprecationWarning | TypeError |
| httpx.get(url, proxies=url) | 200 | TypeError |
| httpx.AsyncClient(proxies=url) | works | TypeError |
| httpx.Client(proxy=url) | 200 | 200 |
| httpx.get(url, proxy=url) | 200 | 200 |
| httpx.Client(mounts={…}) | 200 | 200 |
TypeError: Client.__init__() got an unexpected keyword argument 'proxies'proxy= and mounts= already exist in 0.27, so code written the new way runs on both versions. That makes the fix safe even where you don’t control which httpx gets installed.
One proxy: proxy=
Almost every proxies= in the wild is a single URL, or a dictionary with the same URL for http:// and https://. Both become proxy=url. The proxy URL keeps the http:// scheme even for https:// sites; the TLS connection to the site runs inside the tunnel.
Several proxies: mounts=
mounts= maps URL patterns to transports. A key can be a scheme (https://), a host (https://example.com) or all://; None sends matching requests directly. A transport also takes retries=, which re-tries failed connections; useful with residential exits, as the setup below shows.
SOCKS5 and the environment
proxy="socks5h://…" needs pip install "httpx[socks]"; 0.28 names the missing socksio package, 0.27 rejected socks5h:// as an unknown scheme. Proxy variables still apply: a plain httpx.get() used HTTPS_PROXY on both versions. Pass trust_env=False to ignore them. On our gateway SOCKS5 has its own port, 11000.
Many people hit this error without writing proxies= themselves: a library built on httpx passes it. The best known is the OpenAI SDK. With openai 1.54.0 and httpx 0.28.1, simply creating the client failed:
Update the library first (pip install -U openai). If you can’t, pin httpx<0.28 until you can. And if you wanted a proxy for the SDK anyway, hand it a client you built: OpenAI(http_client=httpx.Client(proxy=url)).
A setup that works
proxy=, mounts= and the async client, on httpx 0.28.1. Ran as shown, twice.
import asyncio
import os
import httpx # 0.28+: proxy= and mounts=, no proxies=
USER = os.environ["PROXY_USER"]
PASS = os.environ["PROXY_PASS"]
PROXY = f"http://{USER}-country-de:{PASS}@via.proxies.vision:9000"
# One proxy for everything: proxy=
with httpx.Client(proxy=PROXY, timeout=30) as client:
print("proxy=", client.get("https://api.ipify.org").text)
# A proxy per scheme or host, the way proxies={...} used to work: mounts=.
# A transport can also retry failed connections: a residential exit
# occasionally drops one before the TLS handshake finishes.
mounts = {
"https://": httpx.HTTPTransport(proxy=PROXY, retries=2),
"http://": httpx.HTTPTransport(proxy=PROXY, retries=2),
"https://example.com": None, # this host goes direct
}
with httpx.Client(mounts=mounts, timeout=30) as client:
print("mounts=", client.get("https://api.ipify.org").text)
# The async client takes the same arguments (AsyncHTTPTransport for mounts).
async def main() -> None:
transport = httpx.AsyncHTTPTransport(proxy=PROXY, retries=2)
async with httpx.AsyncClient(transport=transport, timeout=30) as client:
print("async", (await client.get("https://api.ipify.org")).text)
asyncio.run(main())proxy= 79.214.6.225
mounts= 83.135.184.103
async 79.201.31.167Why the retries
Our first run of this file failed at the second client with ConnectError: [SSL: UNEXPECTED_EOF_WHILE_READING]: the residential exit dropped the connection during the TLS handshake. retries=2 on the transport opens a new connection, which gets a new exit. A new client or a new connection gets a new IP on port 9000; for the same IP across requests use a session label on 10000, as in the rotation article.
Why do I get 'unexpected keyword argument proxies' with httpx?
How do I fix it in the OpenAI Python SDK?
What replaces proxies={'http://': …, 'https://': …}?
Does httpx still use HTTPS_PROXY from the environment?
How do I use a SOCKS5 proxy with httpx?
Keep reading
aiohttp Proxy Errors: ClientHttpProxyError 407, SOCKS5 and trust_env
aiohttp's ClientHttpProxyError explained, why its message leaks your proxy password, socks5:// without aiohttp-socks, and rotation.
6 min read · #python#errors
Scrapy: Could not open CONNECT tunnel with proxy (407, 403, SOCKS5)
What the status in Scrapy's TunnelError means, why socks5:// only times out, and a proxy middleware that works. Every case reproduced.
7 min read · #scrapy#python
SSL: WRONG_VERSION_NUMBER With a Proxy: the Fix for Python, Go, Node and curl
The proxy URL says https:// and the proxy speaks plain HTTP. The same mistake and its error message in requests, httpx, Go, Node and curl.
6 min read · #python#go
Residential proxies, pay per GB
HTTP and SOCKS5. Country, city and sticky sessions in the username. No subscription.