Bug Description
Constructing a default httpx.Client() (with trust_env=True) crashes at startup when the process environment contains a bracketed IPv6 loopback in NO_PROXY / no_proxy, e.g. localhost,127.0.0.1,::1,[::1]. The [::1] entry is treated as a URL, its :1] suffix is parsed as a port, and client construction raises instead of starting.
This bit us in the field: an MCP host process inherited that NO_PROXY value, so every httpx.Client() created by Basic Memory's dependency tree blew up with Invalid port: ':1]' (same signature as the FastEmbed Invalid port failure). Removing just the [::1] entry (keeping bare ::1) fixes it.
Steps To Reproduce
- Install version
0.23.2 (bundles httpx 0.28.1).
- Set the environment (Windows 11, but the parsing bug is platform-independent):
NO_PROXY=localhost,127.0.0.1,::1,[::1]
no_proxy=localhost,127.0.0.1,::1,[::1]
- Run:
import httpx
c = httpx.Client()
- See error (reproduced with the venv interpreter shipped by
uvx --prerelease=allow basic-memory mcp).
Control case: scrubbing the env in-process to NO_PROXY=localhost,127.0.0.1,::1 (bare IPv6, no brackets) plus HTTP_PROXY/HTTPS_PROXY/ALL_PROXY=http://127.0.0.1:7078 constructs the client fine.
Expected Behavior
A bracketed IPv6 loopback in NO_PROXY should be accepted (it is the standard URL-form of ::1, and tools like curl accept it), or at worst that single entry should be skipped with a warning. Client construction must not raise for a bypass-list entry.
Actual Behavior
httpx.Client() raises during __init__:
ValueError: invalid literal for int() with base 10: ':1]'
...
File "httpx/_client.py", line 698, in __init__
URLPattern(key): None
File "httpx/_utils.py", line 172, in __init__
url = URL(pattern)
File "httpx/_urls.py", line 117, in __init__
self._uri_reference = urlparse(url, **kwargs)
File "httpx/_urlparse.py", line 321, in urlparse
parsed_port: int | None = normalize_port(port, scheme)
File "httpx/_urlparse.py", line 411, in normalize_port
raise InvalidURL(f"Invalid port: {port!r}")
httpx.InvalidURL: Invalid port: ':1]'
So any code path that builds a default client while that NO_PROXY value is present fails before doing any work.
Environment
- OS: Windows 11 (10.0.26200)
- Python version: 3.12.12 (venv created by uv)
- Basic Memory version: 0.23.2
- Installation method:
uvx --prerelease=allow basic-memory mcp (uvx 0.11.3)
- Bundled httpx version: 0.28.1
Additional Context
- Triggering value (process env):
NO_PROXY / no_proxy = localhost,127.0.0.1,::1,[::1]. The [::1] entry alone (NO_PROXY=[::1]) is sufficient to reproduce.
- Safe value verified:
localhost,127.0.0.1,::1 (bare ::1, no brackets) works, including with the full proxy set (HTTP_PROXY/HTTPS_PROXY/ALL_PROXY=http://127.0.0.1:port).
- Searched existing issues for NO_PROXY / brackets / httpx / invalid port and found no duplicate.
- The crash happens inside
httpx (_utils.URLPattern <- _client proxy-map build from get_environment_proxies), surfaced through Basic Memory because it is the shipped dependency. If httpx is vendored/pinned here, the fix belongs here; otherwise forwarding the minimal repro upstream to httpx would resolve it.
Possible Solution
Options, cheapest first:
- Sanitize
NO_PROXY/no_proxy entries before they reach URLPattern: strip one pair of surrounding brackets from bracketed IPv6 literals ([::1] -> ::1), consistent with URL host parsing.
- Alternatively, catch
InvalidURL per bypass entry and skip/warn instead of failing client construction.
- Alternatively, construct internal clients with
trust_env=False (or explicit proxy=/no_proxy=) on paths that must never be affected by ambient proxy env.
- If the vendored httpx is old, pick up the upstream fix if one exists for bracketed
NO_PROXY hosts.
Workaround for affected users: drop [::1] from NO_PROXY/no_proxy, keeping localhost,127.0.0.1,::1.
Bug Description
Constructing a default
httpx.Client()(withtrust_env=True) crashes at startup when the process environment contains a bracketed IPv6 loopback inNO_PROXY/no_proxy, e.g.localhost,127.0.0.1,::1,[::1]. The[::1]entry is treated as a URL, its:1]suffix is parsed as a port, and client construction raises instead of starting.This bit us in the field: an MCP host process inherited that
NO_PROXYvalue, so everyhttpx.Client()created by Basic Memory's dependency tree blew up withInvalid port: ':1]'(same signature as the FastEmbedInvalid portfailure). Removing just the[::1]entry (keeping bare::1) fixes it.Steps To Reproduce
0.23.2(bundleshttpx 0.28.1).NO_PROXY=localhost,127.0.0.1,::1,[::1]no_proxy=localhost,127.0.0.1,::1,[::1]uvx --prerelease=allow basic-memory mcp).Control case: scrubbing the env in-process to
NO_PROXY=localhost,127.0.0.1,::1(bare IPv6, no brackets) plusHTTP_PROXY/HTTPS_PROXY/ALL_PROXY=http://127.0.0.1:7078constructs the client fine.Expected Behavior
A bracketed IPv6 loopback in
NO_PROXYshould be accepted (it is the standard URL-form of::1, and tools like curl accept it), or at worst that single entry should be skipped with a warning. Client construction must not raise for a bypass-list entry.Actual Behavior
httpx.Client()raises during__init__:So any code path that builds a default client while that
NO_PROXYvalue is present fails before doing any work.Environment
uvx --prerelease=allow basic-memory mcp(uvx 0.11.3)Additional Context
NO_PROXY/no_proxy=localhost,127.0.0.1,::1,[::1]. The[::1]entry alone (NO_PROXY=[::1]) is sufficient to reproduce.localhost,127.0.0.1,::1(bare::1, no brackets) works, including with the full proxy set (HTTP_PROXY/HTTPS_PROXY/ALL_PROXY=http://127.0.0.1:port).httpx(_utils.URLPattern<-_clientproxy-map build fromget_environment_proxies), surfaced through Basic Memory because it is the shipped dependency. If httpx is vendored/pinned here, the fix belongs here; otherwise forwarding the minimal repro upstream to httpx would resolve it.Possible Solution
Options, cheapest first:
NO_PROXY/no_proxyentries before they reachURLPattern: strip one pair of surrounding brackets from bracketed IPv6 literals ([::1]->::1), consistent with URL host parsing.InvalidURLper bypass entry and skip/warn instead of failing client construction.trust_env=False(or explicitproxy=/no_proxy=) on paths that must never be affected by ambient proxy env.NO_PROXYhosts.Workaround for affected users: drop
[::1]fromNO_PROXY/no_proxy, keepinglocalhost,127.0.0.1,::1.