The Fix
Upgrade to version 0.12.2 or later.
Based on closed Kludex/uvicorn issue #836 · 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.
@@ -7,6 +7,7 @@
import ssl
import sys
+from enum import Enum
from typing import List, Tuple
# server.py
import uvicorn
from starlette.applications import Starlette
app = Starlette()
if __name__ == "__main__":
uvicorn.run(app, host="localhost")
Re-run: python debug/server.py
Option A — Upgrade to fixed release\nUpgrade to version 0.12.2 or later.\nWhen NOT to use: Do not use this fix if the application requires a different host configuration.\n\n
Why This Fix Works in Production
- Trigger: $ python debug/server.py
- Mechanism: The server fails to start due to a ValueError when using 'localhost' as the host
- Why the fix works: Fix reload with ipv6 host addresses to prevent ValueError when using 'localhost'. (first fixed release: 0.12.2).
- If left unfixed, retries/timeouts can trigger duplicate external side-effects (double charges, duplicate emails, repeated writes).
Why This Breaks in Prod
- Shows up under Python 3.9 in real deployments (not just unit tests).
- The server fails to start due to a ValueError when using 'localhost' as the host
- Surfaces as: $ python debug/server.py
Proof / Evidence
- GitHub issue: #836
- Fix PR: https://github.com/encode/uvicorn/pull/803
- First fixed release: 0.12.2
- 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.40
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“@euri10 Oops, just found out that there's a fix in master for this already — #827”
Failure Signature (Search String)
- $ python debug/server.py
Error Message
Stack trace
Error Message
-------------
$ python debug/server.py
INFO: Started server process [86782]
INFO: Waiting for application startup.
INFO: Application startup complete.
Traceback (most recent call last):
File "/Users/florimond/Developer/python-projects/httpx/debug/server.py", line 7, in <module>
uvicorn.run(
File "/Users/florimond/Developer/python-projects/httpx/venv/lib/python3.9/site-packages/uvicorn/main.py", line 391, in run
server.run()
File "/Users/florimond/Developer/python-projects/httpx/venv/lib/python3.9/site-packages/uvicorn/main.py", line 419, in run
loop.run_until_complete(self.serve(sockets=sockets))
File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/Users/florimond/Developer/python-projects/httpx/venv/lib/python3.9/site-packages/uvicorn/main.py", line 436, in serve
await self.startup(sockets=sockets)
File "/Users/florimond/Developer/python-projects/httpx/venv/lib/python3.9/site-packages/uvicorn/main.py", line 526, in startup
if isinstance(ip_address(config.host), IPv6Address):
File "/Users/florimond/.pyenv/versions/3.9.0/lib/python3.9/ipaddress.py", line 53, in ip_address
raise ValueError('%r does not appear to be an IPv4 or IPv6 address' %
ValueError: 'localhost' does not appear to be an IPv4 or IPv6 address
Minimal Reproduction
# server.py
import uvicorn
from starlette.applications import Starlette
app = Starlette()
if __name__ == "__main__":
uvicorn.run(app, host="localhost")
Environment
- Python: 3.9
What Broke
Server fails to start, raising an exception when attempting to bind to 'localhost'.
Why It Broke
The server fails to start due to a ValueError when using 'localhost' as the host
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.12.2 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Option D — Guard side-effects with OnceOnly Guardrail for side-effects
Mitigate duplicate external side-effects under retries/timeouts/agent loops by gating the operation before calling external systems.
- Place OnceOnly between your code/agent and real side-effects (Stripe, emails, CRM, APIs).
- Use a stable key per side-effect (e.g., customer_id + action + idempotency_key).
- Fail-safe: configure fail-open vs fail-closed based on blast radius and spend risk.
- This is most useful when retries/timeouts can re-trigger the same external call.
Show example snippet (optional)
from onceonly import OnceOnly
import os
once = OnceOnly(api_key=os.environ["ONCEONLY_API_KEY"], fail_open=True)
# Stable idempotency key per real side-effect.
# Use a request id / job id / webhook delivery id / Stripe event id, etc.
event_id = "evt_..." # replace
key = f"stripe:webhook:{event_id}"
res = once.check_lock(key=key, ttl=3600)
if res.duplicate:
return {"status": "already_processed"}
# Safe to execute the side-effect exactly once.
handle_event(event_id)
Fix reference: https://github.com/encode/uvicorn/pull/803
First fixed release: 0.12.2
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- Do not use this fix if the application requires a different host configuration.
- Do not use this to hide logic bugs or data corruption. Use it to block duplicate external side-effects and enforce tool permissions/spend caps.
Verify Fix
Re-run: python debug/server.py
Did This Fix Work in Your Case?
Quick signal helps us prioritize which fixes to verify and improve.
Prevention
- 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 |
|---|---|
| 0.12.2 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.