The Fix
Upgrade to version 0.13.0 or later.
Based on closed encode/httpx issue #2047 · PR/commit linked
Production note: This tends to surface only under concurrency. Reproduce with load tests and watch for lock contention/cancellation paths.
@@ -158,17 +158,6 @@ def test_empty_http_version():
-def test_timeout_repr():
- timeout = httpx.TimeoutConfig(timeout=5.0)
- assert repr(timeout) == "TimeoutConfig(timeout=5.0)"
import httpx
import trio
async def download(client, url):
print("started download")
response = await client.get(url)
print(response)
async def close_client(client):
await trio.sleep(1)
print("close client")
await client.aclose()
async def main():
async with httpx.AsyncClient() as client:
async with trio.open_nursery() as nursery:
nursery.start_soon(download, client, "https://speed.hetzner.de/100MB.bin")
nursery.start_soon(close_client, client)
trio.run(main)
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Upgrade to fixed release\nUpgrade to version 0.13.0 or later.\nWhen NOT to use: This fix should not be applied if the application does not handle high concurrency.\n\n
Why This Fix Works in Production
- Trigger: response = await self.ref_client.get_ticker_details_v3(stock, date)
- Mechanism: The issue arises from improper handling of concurrent requests leading to a ValueError
- Why the fix works: Reorganizes timeout config tests and adds new tests for default cases, which may help address issues related to high concurrency in httpx. (first fixed release: 0.13.0).
- If left unfixed, failures can be intermittent under concurrency (hard to reproduce; shows up as sporadic 5xx/timeouts).
Why This Breaks in Prod
- Triggered by an upgrade/regression window: 3.7–3.8 breaks; 0.13.0 is the first fixed release.
- Shows up under Python 3.8 in real deployments (not just unit tests).
- The issue arises from improper handling of concurrent requests leading to a ValueError
- Surfaces as: Traceback (most recent call last):
Proof / Evidence
- GitHub issue: #2047
- Fix PR: https://github.com/encode/httpcore/pull/491
- First fixed release: 0.13.0
- Affected versions: 3.7–3.8
- Reproduced locally: No (not executed)
- Last verified: 2026-02-08
- Confidence: 0.85
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.29
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“That's a great observation, thanks @aworkin. I think the sensible tack there is to inherit BaseException instead of Exception. (Pretty reasonable for resource-closing actions, anyways)”
“For reference, a version of what I saw that triggered this is here: https://github.com/encode/httpx/discussions/2043#discussioncomment-2050790”
“Here's an example that'll raise the same traceback... Which results in...”
“@ahopkins - I've got https://github.com/encode/httpcore/pull/491 to resolve this now”
Failure Signature (Search String)
- response = await self.ref_client.get_ticker_details_v3(stock, date)
Error Message
Stack trace
Error Message
-------------
Traceback (most recent call last):
File "/home/pssolanki/projects/tests/lib_test/test.py", line 86, in get_market_cap
response = await self.ref_client.get_ticker_details_v3(stock, date)
File "/home/pssolanki/projects/openSource/polygon/polygon/reference_apis/reference_api.py", line 875, in get_ticker_details_v3
_res = await self._get_response(_path, params=_data)
File "/home/pssolanki/projects/openSource/polygon/polygon/base_client.py", line 240, in _get_response
_res = await self.session.request('GET', self.BASE + path, params=params)
File "/home/pssolanki/projects/tests/lib_test/venv/lib/python3.8/site-packages/httpx/_client.py", line 1513, in request
return await self.send(request, auth=auth, follow_redirects=follow_redirects)
File "/home/pssolanki/projects/tests/lib_test/venv/lib/python3.8/site-packages/httpx/_client.py", line 1614, in send
raise exc
File "/home/pssolanki/projects/tests/lib_test/venv/lib/python3.8/site-packages/httpx/_client.py", line 1608, in send
await response.aread()
File "/home/pssolanki/projects/tests/lib_test/venv/lib/python3.8/site-packages/httpx/_models.py", line 1662, in aread
self._content = b"".join([part async for part in self.aiter_bytes()])
File "/home/pssolanki/projects/tests/lib_test/venv/lib/python3.8/site-packages/httpx/_models.py", line 1662, in <listcomp>
self._content = b"".join([part asy
... (truncated) ...
Stack trace
Error Message
-------------
python example.py
started download
close_client
Traceback (most recent call last):
File "/Users/tomchristie/GitHub/encode/httpx/httpx/_client.py", line 1601, in send
await response.aread()
File "/Users/tomchristie/GitHub/encode/httpx/httpx/_models.py", line 1662, in aread
self._content = b"".join([part async for part in self.aiter_bytes()])
File "/Users/tomchristie/GitHub/encode/httpx/httpx/_models.py", line 1662, in <listcomp>
self._content = b"".join([part async for part in self.aiter_bytes()])
File "/Users/tomchristie/GitHub/encode/httpx/httpx/_models.py", line 1678, in aiter_bytes
async for raw_bytes in self.aiter_raw():
File "/Users/tomchristie/GitHub/encode/httpx/httpx/_models.py", line 1732, in aiter_raw
async for raw_stream_bytes in self.stream:
File "/Users/tomchristie/GitHub/encode/httpx/httpx/_client.py", line 145, in __aiter__
async for chunk in self._stream:
File "/Users/tomchristie/GitHub/encode/httpx/httpx/_transports/default.py", line 239, in __aiter__
async for part in self._httpcore_stream:
File "/Users/tomchristie/GitHub/encode/httpx/venv/lib/python3.7/site-packages/httpcore/_async/connection_pool.py", line 328, in __aiter__
async for part in self._stream:
File "/Users/tomchristie/GitHub/encode/httpx/venv/lib/python3.7/site-packages/httpcore/_async/http11.py", line 286, in __aiter__
async for chunk in sel
... (truncated) ...
Minimal Reproduction
import httpx
import trio
async def download(client, url):
print("started download")
response = await client.get(url)
print(response)
async def close_client(client):
await trio.sleep(1)
print("close client")
await client.aclose()
async def main():
async with httpx.AsyncClient() as client:
async with trio.open_nursery() as nursery:
nursery.start_soon(download, client, "https://speed.hetzner.de/100MB.bin")
nursery.start_soon(close_client, client)
trio.run(main)
Environment
- Python: 3.8
What Broke
Users experience ValueErrors when making multiple concurrent requests, causing disruptions.
Why It Broke
The issue arises from improper handling of concurrent requests leading to a ValueError
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.13.0 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Fix reference: https://github.com/encode/httpcore/pull/491
First fixed release: 0.13.0
Last verified: 2026-02-08. Validate in your environment.
When NOT to Use This Fix
- This fix should not be applied if the application does not handle high concurrency.
Verify Fix
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Did This Fix Work in Your Case?
Quick signal helps us prioritize which fixes to verify and improve.
Prevention
- Add a CI check that diffs key outputs after upgrades (OpenAPI schema snapshots, JSON payload shapes, CLI output).
- Upgrade behind a canary and run integration tests against the canary before 100% rollout.
- Add a stress test that runs high-concurrency workloads and fails on thread dumps / blocked locks.
- Enable watchdog dumps in prod (faulthandler, thread dump endpoint) to capture deadlocks quickly.
Version Compatibility Table
| Version | Status |
|---|---|
| 3.7 | Broken |
| 3.8 | Broken |
| 0.13.0 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.