The Fix
pip install urllib3==2.3.0
Based on closed urllib3/urllib3 issue #2868 · PR/commit linked
@@ -0,0 +1 @@
@@ -0,0 +1 @@
+Added ``HTTPResponse.shutdown()`` to stop any ongoing or future reads for a specific response. It calls ``shutdown(SHUT_RD)`` on the underlying socket.
diff --git a/src/urllib3/connection.py b/src/urllib3/connection.py
index 4195ee0306..591ac407bc 100644
main [MainThread] starting server
server [Thread-1] listening on port 10000
main [MainThread] starting client
client [Thread-2] opening connection
main [MainThread] sleeping a while
server [Thread-1] starting stream
127.0.0.1 - - [05/Jan/2023 13:38:11] "GET / HTTP/1.1" 200 -
server [Thread-1] wrote 10 bytes
client [Thread-2] reading data
client [Thread-2] read 10 bytes
main [MainThread] about to close response
main [MainThread] closed response
client [Thread-2] failed: <some kind of I/O error>
client [Thread-2] no longer reading
main [MainThread] about to clear connection pool
main [MainThread] cleared connection pool
main [MainThread] exiting
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Upgrade to fixed release\npip install urllib3==2.3.0\nWhen NOT to use: This fix should not be used if the application requires blocking reads to complete before closing.\n\n
Why This Fix Works in Production
- Trigger: trying to close a response hangs if a blocking read is happening on another thread
- Mechanism: Added HTTPResponse.shutdown() to stop blocking reads, allowing the client to handle socket errors appropriately.
- Why the fix works: Added HTTPResponse.shutdown() to stop blocking reads, allowing the client to handle socket errors appropriately. (first fixed release: 2.3.0).
- If left unfixed, failures can be intermittent under concurrency (hard to reproduce; shows up as sporadic 5xx/timeouts).
Why This Breaks in Prod
- Shows up under Python 3.7.13 in real deployments (not just unit tests).
- Production symptom (often without a traceback): trying to close a response hangs if a blocking read is happening on another thread
Proof / Evidence
- GitHub issue: #2868
- Fix PR: https://github.com/urllib3/urllib3/pull/3527
- First fixed release: 2.3.0
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.95
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.50
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“Here's something I just came up with that appears to work, but it's pretty hacky and I'm not sure how portable it is: When I…”
“Using the socket module to have a thread reading from a socket and another one closing it, while the server is sending chunks of data…”
“Have you tried doing the same things with plain sockets? This would probably help understanding the issue better.”
“@pquentin I'm not sure what you mean by "the same things."”
Failure Signature (Search String)
- trying to close a response hangs if a blocking read is happening on another thread
- I hoped that closing the response would cause the underlying socket to be closed, causing the client thread to get a read error and terminate. For this demo app, the output would
Copy-friendly signature
Failure Signature
-----------------
trying to close a response hangs if a blocking read is happening on another thread
I hoped that closing the response would cause the underlying socket to be closed, causing the client thread to get a read error and terminate. For this demo app, the output would look like this:
Error Message
Signature-only (no traceback captured)
Error Message
-------------
trying to close a response hangs if a blocking read is happening on another thread
I hoped that closing the response would cause the underlying socket to be closed, causing the client thread to get a read error and terminate. For this demo app, the output would look like this:
Minimal Reproduction
main [MainThread] starting server
server [Thread-1] listening on port 10000
main [MainThread] starting client
client [Thread-2] opening connection
main [MainThread] sleeping a while
server [Thread-1] starting stream
127.0.0.1 - - [05/Jan/2023 13:38:11] "GET / HTTP/1.1" 200 -
server [Thread-1] wrote 10 bytes
client [Thread-2] reading data
client [Thread-2] read 10 bytes
main [MainThread] about to close response
main [MainThread] closed response
client [Thread-2] failed: <some kind of I/O error>
client [Thread-2] no longer reading
main [MainThread] about to clear connection pool
main [MainThread] cleared connection pool
main [MainThread] exiting
Environment
- Python: 3.7.13
- urllib3: 1.26.13
What Broke
The application hangs indefinitely when attempting to close a response while another thread is reading data.
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
pip install urllib3==2.3.0
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/3527
First fixed release: 2.3.0
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix should not be used if the application requires blocking reads to complete before closing.
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 |
|---|---|
| 2.3.0 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.