You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
🏷️ This issue is part of HTTPXodus, a community effort to help major projects plan their path off the stalled httpx stable line onto httpx2, the actively maintained fork by Pydantic Services (with original httpx author Tom Christie involved). One coordinated issue per project — no spam, no drive-by PRs.
Background — what happened to httpx
httpx is one of the most important HTTP clients in the Python ecosystem (370k+ dependent repositories). However:
The last stable release is 0.28.1 (December 2024) — over 20 months ago.
For most of 2025 the repository was dormant; maintenance trackers (e.g. Snyk) now flag it as inactive.
Encouragingly, the project has recently resumed activity: 1.0.dev4–dev6 shipped between 2026-08-19 and 2026-08-31. A 1.0 is clearly in the works, but there is no committed date for a stable 1.0, and the dev line carries breaking changes.
Meanwhile, the ecosystem has already begun moving. Projects that have adopted httpx2:
httpx2 is a fork of httpx 0.28.1 maintained by Pydantic Services Inc., with Tom Christie involved. It is actively released (v2.0.0 → v2.12.0 since May 2026) and keeps a compatible public API:
importhttpx2r=httpx2.get("https://example.org")
Why migrate — the benefits
Active maintenance — regular releases, reviewed PRs, and a funded maintainer team, versus an uncertain stable-release timeline.
Modern TLS by default — certificates are verified against the OS trust store instead of the bundled certifi, removing a common source of stale-CA issues.
New capabilities — built-in Server-Sent Events (client.sse()) and WebSocket support (httpx2[ws]), without extra dependencies.
Ecosystem alignment — as frameworks and SDKs migrate, staying on httpx increasingly means duplicate HTTP stacks in one dependency tree.
Risks of staying on httpx
Security exposure: no stable-line releases means no stable-line security fixes. If a CVE lands in 0.28.x today, there is no maintained branch to patch it.
Dependency conflicts: packages that pin httpx<1.0 already conflict with migrated peers (see e.g. the langfuse discussion); the longer the wait, the worse the resolver pain for downstream users.
Compounding migration cost: the gap between 0.28.x and whatever 1.0 becomes keeps growing; migrating to httpx2 now is a small, well-documented step (official migration guide: https://pydantic.dev/docs/httpx2/get-started/migration/).
What migration could look like here
In Chroma, httpx is the transport that connects the Python client to a Chroma server (and to Chroma Cloud). It sits behind the public constructors chromadb.HttpClient(), chromadb.AsyncHttpClient(), and chromadb.CloudClient(), which build on three files in chromadb/api/:
chromadb/api/fastapi.py — class FastAPI(BaseHTTPClient, ServerAPI): the sync client. Constructs an httpx.Client and stores it as the private self._session.
chromadb/api/async_fastapi.py — class AsyncFastAPI(BaseHTTPClient, AsyncServerAPI): the async client. Constructs an httpx.AsyncClient per event loop, stored in _clients: Dict[int, httpx.AsyncClient].
chromadb/api/base_http_client.py — class BaseHTTPClient: shared base that builds the connection httpx.Limits and maps error responses.
Two properties of this design make a migration here comparatively low-risk:
httpx is essentially an implementation detail. Callers cannot inject their own httpx client, and every response is parsed to JSON (orjson.loads(response.text)) before being returned — so httpx.Response never leaks into the results users receive. The only httpx type on the importable surface is httpx.Limits, exposed via the public BaseHTTPClient.http_limits property.
Usage is concentrated. Beyond the client layer, only a couple of embedding functions touch httpx directly — chromadb/utils/embedding_functions/jina_embedding_function.py (self._session = httpx.Client()) and roboflow_embedding_function.py (a lazy importlib.import_module("httpx")). The other remote embedding providers (OpenAI, Mistral, Ollama, Baseten, …) go through their vendor SDKs, so their HTTP layer is those SDKs' concern, not Chroma's.
Two viable paths, depending on your compatibility goals:
Option A — dual support (recommended for libraries): prefer httpx2 when available, fall back to httpx:
with httpx2; python_version >= "3.10" added as an extra/optional dependency. This is the natural fit here for two reasons: Chroma is a published library (pip install chromadb), and Chroma currently supports Python ≥ 3.9 while httpx2 requires Python ≥ 3.10 — so the marker lets 3.10+ users get httpx2 while 3.9 keeps working on httpx. Because the public surface barely exposes httpx types, the import httpx2 as httpx alias keeps http_limits (→ httpx.Limits) and the rest of the client working unchanged.
Option B — hard switch (fine for applications / next major): replace httpx>=0.27.0 with httpx2>=2.12 outright and switch imports to import httpx2 as httpx. Requires bumping requires-python to >=3.10, i.e. dropping Python 3.9 support — a bigger commitment, so probably one for a future major release.
⚠️One caveat worth calling out: httpx2's move to the OS trust store can change TLS behavior in containers and corporate-proxy environments that relied on certifi's bundle. Worth a note in your changelog either way.
Notes
No duplication: as of 2026-09-02 there is no existing httpx2-related issue or PR in this repo (GitHub search httpx2 → 0 results; search API total_count = 0), and no issue proposing a move to httpx 1.0. This issue would not duplicate anything.
Dependency: httpx>=0.27.0 is a core runtime dependency — declared in pyproject.toml[project].dependencies and in requirements.txt — not optional and not dev-only. It backs both the self-hosted-server client path and the CloudClient (Chroma Cloud) path.
Python floor: requires-python = ">=3.9" in pyproject.toml. This is the main reason Option A (dual import with a python_version >= "3.10" marker) is the lower-friction path; Option B implies dropping 3.9.
Happy to open a PR for either option if the maintainers are interested — and equally happy to close this if you'd rather wait for httpx 1.0 stable. No pressure; the goal is just to make sure the decision is an informed one. 🙏
Background — what happened to httpx
httpxis one of the most important HTTP clients in the Python ecosystem (370k+ dependent repositories). However:1.0.dev4–dev6shipped between 2026-08-19 and 2026-08-31. A 1.0 is clearly in the works, but there is no committed date for a stable 1.0, and the dev line carries breaking changes.Meanwhile, the ecosystem has already begun moving. Projects that have adopted
httpx2:What is httpx2
httpx2is a fork of httpx 0.28.1 maintained by Pydantic Services Inc., with Tom Christie involved. It is actively released (v2.0.0 → v2.12.0 since May 2026) and keeps a compatible public API:Why migrate — the benefits
certifi, removing a common source of stale-CA issues.client.sse()) and WebSocket support (httpx2[ws]), without extra dependencies.Risks of staying on httpx
httpx<1.0already conflict with migrated peers (see e.g. the langfuse discussion); the longer the wait, the worse the resolver pain for downstream users.What migration could look like here
In Chroma,
httpxis the transport that connects the Python client to a Chroma server (and to Chroma Cloud). It sits behind the public constructorschromadb.HttpClient(),chromadb.AsyncHttpClient(), andchromadb.CloudClient(), which build on three files inchromadb/api/:chromadb/api/fastapi.py—class FastAPI(BaseHTTPClient, ServerAPI): the sync client. Constructs anhttpx.Clientand stores it as the privateself._session.chromadb/api/async_fastapi.py—class AsyncFastAPI(BaseHTTPClient, AsyncServerAPI): the async client. Constructs anhttpx.AsyncClientper event loop, stored in_clients: Dict[int, httpx.AsyncClient].chromadb/api/base_http_client.py—class BaseHTTPClient: shared base that builds the connectionhttpx.Limitsand maps error responses.Two properties of this design make a migration here comparatively low-risk:
orjson.loads(response.text)) before being returned — sohttpx.Responsenever leaks into the results users receive. The only httpx type on the importable surface ishttpx.Limits, exposed via the publicBaseHTTPClient.http_limitsproperty.chromadb/utils/embedding_functions/jina_embedding_function.py(self._session = httpx.Client()) androboflow_embedding_function.py(a lazyimportlib.import_module("httpx")). The other remote embedding providers (OpenAI, Mistral, Ollama, Baseten, …) go through their vendor SDKs, so their HTTP layer is those SDKs' concern, not Chroma's.Two viable paths, depending on your compatibility goals:
Option A — dual support (recommended for libraries): prefer httpx2 when available, fall back to httpx:
with
httpx2; python_version >= "3.10"added as an extra/optional dependency. This is the natural fit here for two reasons: Chroma is a published library (pip install chromadb), and Chroma currently supports Python ≥ 3.9 while httpx2 requires Python ≥ 3.10 — so the marker lets 3.10+ users get httpx2 while 3.9 keeps working on httpx. Because the public surface barely exposes httpx types, theimport httpx2 as httpxalias keepshttp_limits(→httpx.Limits) and the rest of the client working unchanged.Option B — hard switch (fine for applications / next major): replace
httpx>=0.27.0withhttpx2>=2.12outright and switch imports toimport httpx2 as httpx. Requires bumpingrequires-pythonto>=3.10, i.e. dropping Python 3.9 support — a bigger commitment, so probably one for a future major release.Notes
httpx2→ 0 results; search APItotal_count = 0), and no issue proposing a move to httpx 1.0. This issue would not duplicate anything.httpx>=0.27.0is a core runtime dependency — declared inpyproject.toml[project].dependenciesand inrequirements.txt— not optional and not dev-only. It backs both the self-hosted-server client path and theCloudClient(Chroma Cloud) path.requires-python = ">=3.9"inpyproject.toml. This is the main reason Option A (dual import with apython_version >= "3.10"marker) is the lower-friction path; Option B implies dropping 3.9.HttpEmbeddingFunction— worth being aware of in either direction.)Happy to open a PR for either option if the maintainers are interested — and equally happy to close this if you'd rather wait for httpx 1.0 stable. No pressure; the goal is just to make sure the decision is an informed one. 🙏