Jump to solution
Verify

The Fix

pip install urllib3==1.25

Based on closed urllib3/urllib3 issue #718 · PR/commit linked

Production note: This usually shows up under retries/timeouts. Treat it as a side-effect risk until you can verify behavior with a canary + real traffic.

Jump to Verify Open PR/Commit
@@ -130,8 +130,8 @@ def __init__(self, body='', headers=None, status=0, version=0, reason=None, self.chunked = True - # We certainly don't want to preload content when the response is chunked. - if not self.chunked and preload_content and not self._body: + # If requested, preload the body.
repro.py
http = HTTPConnectionPool("localhost", 4001, maxsize=2) while True: try: resp = http.request("GET", "http://localhost:4001/v2/keys/calico/v1", fields={"recursive": "true", "wait": "true", "waitIndex": next_index}, timeout=5) resp_body = loads(resp.data) except ReadTimeoutError: _log.info("Watch read timed out, restarting watch at index %s", next_index) continue else: ...
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
Option A — Upgrade to fixed release\npip install urllib3==1.25\nWhen NOT to use: This fix should not be used if the application relies on the previous behavior of not preloading chunked responses.\n\n

Why This Fix Works in Production

  • Trigger: 2015-10-15 10:52:03,594 [INFO][46889/140035896854272] __main__ 64: About to call http.request...
  • Mechanism: The connection handling for chunked responses was not correctly implemented, causing ReadTimeoutError
  • Why the fix works: Resolves the issue by allowing chunked bodies to be preloaded correctly, addressing the ReadTimeoutError experienced during long-poll reads. (first fixed release: 1.25).
Production impact:
  • If left unfixed, retry loops can amplify load and turn a small outage into a cascade (thundering herd).

Why This Breaks in Prod

  • Shows up under Python 2.7 in real deployments (not just unit tests).
  • The connection handling for chunked responses was not correctly implemented, causing ReadTimeoutError
  • Surfaces as: 2015-10-15 10:52:03,594 [INFO][46889/140035896854272] __main__ 64: About to call http.request...

Proof / Evidence

  • GitHub issue: #718
  • Fix PR: https://github.com/urllib3/urllib3/pull/722
  • First fixed release: 1.25
  • Reproduced locally: No (not executed)
  • Last verified: 2026-02-09
  • Confidence: 0.85
  • Did this fix it?: Yes (upstream fix exists)
  • Own content ratio: 0.39

Discussion

High-signal excerpts from the issue thread (symptoms, repros, edge-cases).

“This is using normal Threads on Python 2.7, no gevent monkeypatching going on.”
@fasaxc · 2015-10-15 · source
“So just to clarify, when the 5s delay occurs on the _second_ call to request(), before either of those logs is emitted?”
@Lukasa · 2015-10-15 · source
“Hmm, I'm a little bit interested in where your ReadTimeoutError is coming from. My suspicion is that you should be getting some retries before that…”
@Lukasa · 2015-10-15 · source
“Adjusted my script to give better diags: Yes, there's a 5s delay after the second call to request. In case it helps, etcd pushes its…”
@fasaxc · 2015-10-15 · source

Failure Signature (Search String)

  • 2015-10-15 10:52:03,594 [INFO][46889/140035896854272] __main__ 64: About to call http.request...

Error Message

Stack trace
error.txt
Error Message ------------- 2015-10-15 10:52:03,594 [INFO][46889/140035896854272] __main__ 64: About to call http.request... 2015-10-15 10:52:03,596 [INFO][46889/140035896854272] urllib3.connectionpool 207: Starting new HTTP connection (1): localhost 2015-10-15 10:52:03,598 [DEBUG][46889/140035896854272] urllib3.connectionpool 387: "GET http://localhost:4001/v2/keys/calico/v1?waitIndex=7653237&recursive=true&wait=true HTTP/1.1" 200 None 2015-10-15 10:52:08,604 [ERROR][46889/140035896854272] __main__ 72: Watch read timed out, restarting watch at index 7653237 Traceback (most recent call last): File "calico/felix/readetcd.py", line 69, in watch_etcd resp_body = loads(resp.data) File "/home/gulfstream/git/calico/env27/local/lib/python2.7/site-packages/urllib3/response.py", line 164, in data return self.read(cache_content=True) File "/home/gulfstream/git/calico/env27/local/lib/python2.7/site-packages/urllib3/response.py", line 292, in read flush_decoder = True File "/usr/lib/python2.7/contextlib.py", line 35, in __exit__ self.gen.throw(type, value, traceback) File "/home/gulfstream/git/calico/env27/local/lib/python2.7/site-packages/urllib3/response.py", line 219, in _error_catcher raise ReadTimeoutError(self._pool, None, 'Read timed out.') ReadTimeoutError: HTTPConnectionPool(host='localhost', port=4001): Read timed out. 2015-10-15 10:52:08,606 [INFO][46889/140035896854272] __mai ... (truncated) ...

Minimal Reproduction

repro.py
http = HTTPConnectionPool("localhost", 4001, maxsize=2) while True: try: resp = http.request("GET", "http://localhost:4001/v2/keys/calico/v1", fields={"recursive": "true", "wait": "true", "waitIndex": next_index}, timeout=5) resp_body = loads(resp.data) except ReadTimeoutError: _log.info("Watch read timed out, restarting watch at index %s", next_index) continue else: ...

Environment

  • Python: 2.7
  • urllib3: 1.12

What Broke

Users experienced unexpected delays and ReadTimeoutError during long-poll reads.

Why It Broke

The connection handling for chunked responses was not correctly implemented, causing ReadTimeoutError

Fix Options (Details)

Option A — Upgrade to fixed release Safe default (recommended)

pip install urllib3==1.25

When NOT to use: This fix should not be used if the application relies on the previous behavior of not preloading chunked responses.

Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.

Fix reference: https://github.com/urllib3/urllib3/pull/722

First fixed release: 1.25

Last verified: 2026-02-09. Validate in your environment.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • This fix should not be used if the application relies on the previous behavior of not preloading chunked responses.

Verify Fix

verify
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.
  • Track RSS + object counts after deployments; alert on monotonic growth and GC pressure.
  • Add a long-running test that repeats the failing call path and asserts stable memory.

Version Compatibility Table

VersionStatus
1.25 Fixed

Related Issues

No related fixes found.

Sources

We don’t republish the full GitHub discussion text. Use the links above for context.