Jump to solution
Verify

The Fix

pip install urllib3==1.25.9

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

Production note: This tends to surface only under concurrency. Reproduce with load tests and watch for lock contention/cancellation paths.

Jump to Verify Open PR/Commit
@@ -297,5 +297,8 @@ In chronological order: * Test improvements +* Chris Olufson <[email protected]> + * Fix for connection not being released on HTTP redirect and response not preloaded +
repro.py
import logging from pathlib import Path import shutil import urllib3 _logger = logging.getLogger(__name__) _BUFFER_SIZE = 1024 * 1024 # buffer for downloading remote resource url_headers = urllib3.make_headers(keep_alive=True, accept_encoding=True) url_retries = urllib3.Retry(total=2, backoff_factor=1, status_forcelist=[500, 502, 503, 504]) url_client = urllib3.PoolManager(timeout=urllib3.Timeout(total=15.0), retries=url_retries, block=True, headers=url_headers) def stream_response(url: str, filepath: Path, id: int): # Must call release_conn() after file copied but opening/writing exception is possible rsp = None try: _logger.debug(f'> {id:4d} GET: {url}') rsp = url_client.request('GET', url, preload_content=False) _logger.debug(f'> {id:4d} resp code: {rsp.status}') if rsp.status == 200: _logger.debug(f'> {id:4d} writing: "{filepath.name}"') with filepath.open('wb', buffering=_BUFFER_SIZE) as rfp: shutil.copyfileobj(rsp, rfp, length=_BUFFER_SIZE) except Exception as ex: _logger.exception(f'> {id:4d} Error') finally: if rsp: rsp.release_conn() return rsp.status logging.basicConfig(level=logging.DEBUG, handlers=[logging.FileHandler('output.log', mode='w'), logging.StreamHandler()]) logging.captureWarnings(True) _logger.info('Started') items = [ ['https://fwd.aws/v3mz8', Path('d1.pdf')], ['https://fwd.aws/88JKk', Path('d2.pdf')], ['https://fwd.aws/D9yDG', Path('d3.pdf')], ['https://fwd.aws/NmXza', Path('d4.pdf')], ['https://fwd.aws/NmXza', Path('d5.pdf')] ] for id, it in enumerate(items): stream_response(it[0], it[1], id)
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.9\nWhen NOT to use: Do not use this fix if your application relies on blocking behavior for connection management.\n\nOption C — Workaround\ndoes not help for you. Are you sure you're using the exact example in your first post?\nWhen NOT to use: Do not use this fix if your application relies on blocking behavior for connection management.\n\n

Why This Fix Works in Production

  • Trigger: urllib3 hanging inside call to PoolManager request
  • Mechanism: The connection was not properly released after HTTP redirects, causing hangs
  • Why the fix works: Addresses the issue of urllib3 hanging inside PoolManager requests by ensuring that connections are properly drained and released after redirects. (first fixed release: 1.25.9).
Production impact:
  • 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.8.2 in real deployments (not just unit tests).
  • The connection was not properly released after HTTP redirects, causing hangs
  • Production symptom (often without a traceback): urllib3 hanging inside call to PoolManager request

Proof / Evidence

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

Discussion

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

“Thanks for the full example! Can you try setting block=False when instantiating urllib3.PoolManager to see if it helps?”
@pquentin · 2020-03-07 · source
“Hi @pquentin I tried setting block=False as you suggested, and it made no difference. The call to urllib3.PoolManager request still hangs and never returns”
@tycarac · 2020-03-08 · source
“@tycarac That's great to hear! I'd be happy to assist if you have any difficulties”
@pquentin · 2020-03-09 · source
“Lots of firsts indeed! Congratulations on the progress! For your next pull request you can try following https://guides.github.com/activities/hello-world/ but for this one can you please…”
@pquentin · 2020-03-16 · source

Failure Signature (Search String)

  • urllib3 hanging inside call to PoolManager request
  • I have a repeatable issue with urllib3 hanging inside PoolManager request for an unusual edge case. I have repeated this issue on two separate machines.
Copy-friendly signature
signature.txt
Failure Signature ----------------- urllib3 hanging inside call to PoolManager request I have a repeatable issue with urllib3 hanging inside PoolManager request for an unusual edge case. I have repeated this issue on two separate machines.

Error Message

Signature-only (no traceback captured)
error.txt
Error Message ------------- urllib3 hanging inside call to PoolManager request I have a repeatable issue with urllib3 hanging inside PoolManager request for an unusual edge case. I have repeated this issue on two separate machines.

Minimal Reproduction

repro.py
import logging from pathlib import Path import shutil import urllib3 _logger = logging.getLogger(__name__) _BUFFER_SIZE = 1024 * 1024 # buffer for downloading remote resource url_headers = urllib3.make_headers(keep_alive=True, accept_encoding=True) url_retries = urllib3.Retry(total=2, backoff_factor=1, status_forcelist=[500, 502, 503, 504]) url_client = urllib3.PoolManager(timeout=urllib3.Timeout(total=15.0), retries=url_retries, block=True, headers=url_headers) def stream_response(url: str, filepath: Path, id: int): # Must call release_conn() after file copied but opening/writing exception is possible rsp = None try: _logger.debug(f'> {id:4d} GET: {url}') rsp = url_client.request('GET', url, preload_content=False) _logger.debug(f'> {id:4d} resp code: {rsp.status}') if rsp.status == 200: _logger.debug(f'> {id:4d} writing: "{filepath.name}"') with filepath.open('wb', buffering=_BUFFER_SIZE) as rfp: shutil.copyfileobj(rsp, rfp, length=_BUFFER_SIZE) except Exception as ex: _logger.exception(f'> {id:4d} Error') finally: if rsp: rsp.release_conn() return rsp.status logging.basicConfig(level=logging.DEBUG, handlers=[logging.FileHandler('output.log', mode='w'), logging.StreamHandler()]) logging.captureWarnings(True) _logger.info('Started') items = [ ['https://fwd.aws/v3mz8', Path('d1.pdf')], ['https://fwd.aws/88JKk', Path('d2.pdf')], ['https://fwd.aws/D9yDG', Path('d3.pdf')], ['https://fwd.aws/NmXza', Path('d4.pdf')], ['https://fwd.aws/NmXza', Path('d5.pdf')] ] for id, it in enumerate(items): stream_response(it[0], it[1], id)

Environment

  • Python: 3.8.2

What Broke

Requests hang indefinitely during PoolManager calls, leading to application stalls.

Why It Broke

The connection was not properly released after HTTP redirects, causing hangs

Fix Options (Details)

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

pip install urllib3==1.25.9

When NOT to use: Do not use this fix if your application relies on blocking behavior for connection management.

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

Option C — Workaround Temporary workaround

does not help for you. Are you sure you're using the exact example in your first post?

When NOT to use: Do not use this fix if your application relies on blocking behavior for connection management.

Use only if you cannot change versions today. Treat this as a stopgap and remove once upgraded.

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

First fixed release: 1.25.9

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

  • Do not use this fix if your application relies on blocking behavior for connection management.

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.
  • 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

VersionStatus
1.25.9 Fixed

Related Issues

No related fixes found.

Sources

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