Jump to solution
Verify

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

Jump to Verify Open PR/Commit
@@ -116,5 +116,20 @@ def test_cli_incomplete_app_parameter() -> None: +def test_cli_reloader_incomplete_app_parameter( + capfd: pytest.CaptureFixture[str], +) -> None:
repro.py
# test.py from fastapi import FastAPI app = FastAPI() @app.on_event("startup") def startup(): raise Exception("Hi")
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
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
Production impact:
  • 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

Discussion

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

“Just to give more details..”
@Kludex · 2022-05-15 · confirmation · source
“You shouldn't be using uvicorn's --workers feature in production”
@Kludex · 2021-12-01 · source
“Just want to point out that this is still an issue on 0.17.0.post1.”
@Korijn · 2022-02-02 · source
“I would check how gunicorn and hypercorn are doing it.”
@Kludex · 2021-08-21 · source

Failure Signature (Search String)

  • ❯ uvicorn test:app --reload

Error Message

Stack trace
error.txt
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.txt
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

repro.py
# 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.

When NOT to use: This fix is not applicable if you rely on hanging behavior for daemon processes.

Option C — Workaround Temporary workaround

can be found on the first commit of #1177.

When NOT to use: This fix is not applicable if you rely on hanging behavior for daemon processes.

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.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • This fix is not applicable if you rely on hanging behavior for daemon processes.

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

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