The Fix
Adds a check to ensure child processes are alive and shuts down instead of hanging when startup fails.
Based on closed Kludex/uvicorn issue #1115 · PR/commit linked
Production note: Most teams hit this during upgrades or environment changes. Roll out with a canary and smoke critical endpoints (health, OpenAPI/docs) before 100%.
@@ -116,5 +116,20 @@ def test_cli_incomplete_app_parameter() -> None:
+def test_cli_reloader_incomplete_app_parameter(
+ capfd: pytest.CaptureFixture[str],
+) -> None:
# test.py
from fastapi import FastAPI
app = FastAPI()
@app.on_event("startup")
def startup():
raise Exception("Hi")
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Apply the official fix\nAdds a check to ensure child processes are alive and shuts down instead of hanging when startup fails.\nWhen NOT to use: This fix is not applicable if you rely on hanging behavior for daemon processes.\n\nOption C — Workaround\ncan be found on the first commit of #1177.\nWhen NOT to use: This fix is not applicable if you rely on hanging behavior for daemon processes.\n\n
Why This Fix Works in Production
- Trigger: ❯ uvicorn test:app --reload
- Mechanism: The main process does not terminate when startup fails with multiple workers
- If left unfixed, the same config can fail only in production (env differences), causing startup failures or partial feature outages.
Why This Breaks in Prod
- Shows up under Python 3.8 in real deployments (not just unit tests).
- The main process does not terminate when startup fails with multiple workers
- Surfaces as: ❯ uvicorn test:app --reload
Proof / Evidence
- GitHub issue: #1115
- Fix PR: https://github.com/kludex/uvicorn/pull/1177
- Reproduced locally: No (not executed)
- Last verified: 2026-02-12
- Confidence: 0.70
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.30
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“Just to give more details..”
“You shouldn't be using uvicorn's --workers feature in production”
“Just want to point out that this is still an issue on 0.17.0.post1.”
“I would check how gunicorn and hypercorn are doing it.”
Failure Signature (Search String)
- ❯ uvicorn test:app --reload
Error Message
Stack trace
Error Message
-------------
❯ uvicorn test:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [40026] using watchgod
INFO: Started server process [40028]
INFO: Waiting for application startup.
ERROR: Traceback (most recent call last):
File "/home/marcelo/anaconda3/envs/uvicorn/lib/python3.8/site-packages/starlette/routing.py", line 540, in lifespan
async for item in self.lifespan_context(app):
File "/home/marcelo/anaconda3/envs/uvicorn/lib/python3.8/site-packages/starlette/routing.py", line 481, in default_lifespan
await self.startup()
File "/home/marcelo/anaconda3/envs/uvicorn/lib/python3.8/site-packages/starlette/routing.py", line 518, in startup
handler()
File "/home/marcelo/Development/./test.py", line 7, in startup
raise Exception("Hi")
Exception: Hi
ERROR: Application startup failed. Exiting.
Stack trace
Error Message
-------------
❯ uvicorn test:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [40674] using watchgod
INFO: Started server process [40676]
INFO: Waiting for application startup.
ERROR: Traceback (most recent call last):
File "/home/marcelo/anaconda3/envs/uvicorn/lib/python3.8/site-packages/starlette/routing.py", line 540, in lifespan
async for item in self.lifespan_context(app):
File "/home/marcelo/anaconda3/envs/uvicorn/lib/python3.8/site-packages/starlette/routing.py", line 481, in default_lifespan
await self.startup()
File "/home/marcelo/anaconda3/envs/uvicorn/lib/python3.8/site-packages/starlette/routing.py", line 518, in startup
handler()
File "/home/marcelo/Development/./test.py", line 7, in startup
raise Exception("Hi")
Exception: Hi
ERROR: Application startup failed. Exiting.
WARNING: WatchGodReload detected file change in '['/home/marcelo/Development/test.py']'. Reloading...
INFO: Started server process [40734]
INFO: Waiting for application startup.
ERROR: Traceback (most recent call last):
File "/home/marcelo/anaconda3/envs/uvicorn/lib/python3.8/site-packages/starlette/routing.py", line 540, in lifespan
async for item in self.lifespan_context(app):
File "/home/marcelo/anaconda3/envs/uvicorn/lib/python3.8/site-packages/starlette/routing.py",
... (truncated) ...
Minimal Reproduction
# test.py
from fastapi import FastAPI
app = FastAPI()
@app.on_event("startup")
def startup():
raise Exception("Hi")
Environment
- Python: 3.8
What Broke
The application hangs indefinitely instead of exiting on startup failure.
Why It Broke
The main process does not terminate when startup fails with multiple workers
Fix Options (Details)
Option A — Apply the official fix
Adds a check to ensure child processes are alive and shuts down instead of hanging when startup fails.
Option C — Workaround Temporary workaround
can be found on the first commit of #1177.
Use only if you cannot change versions today. Treat this as a stopgap and remove once upgraded.
Fix reference: https://github.com/kludex/uvicorn/pull/1177
Last verified: 2026-02-12. Validate in your environment.
When NOT to Use This Fix
- This fix is not applicable if you rely on hanging behavior for daemon processes.
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
- Capture the exact failing error string in logs and tests so you can reproduce via a minimal script.
- Pin production dependencies and upgrade only with a reproducible test that hits the failing path.
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.