The Fix
Upgrade to version 0.13.3 or later.
Based on closed Kludex/uvicorn issue #896 · 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%.
@@ -1,5 +1,6 @@
import asyncio
import logging
+import signal
from gunicorn.workers.base import Worker
import logging
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
logging.basicConfig(level=logging.DEBUG, filename='./log.txt')
logger = logging.getLogger(__name__)
async def some_startup_task():
logger.info("startup")
async def some_shutdown_task():
logger.info("shutdown")
async def homepage(request):
logger.debug("homepage()")
return JSONResponse({'hello': 'world'})
app = Starlette(debug=False,
routes=[Route('/', homepage)],
on_startup=[some_startup_task],
on_shutdown=[some_shutdown_task])
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Upgrade to fixed release\nUpgrade to version 0.13.3 or later.\nWhen NOT to use: Do not use if it changes public behavior or if the failure cannot be reproduced.\n\n
Why This Fix Works in Production
- Trigger: this 10 times does not log to any access log.
- Mechanism: UvicornWorker does not reset signals correctly, causing issues with log rotation
- Why the fix works: Fix resetting signals in Gunicorn UvicornWorker to ensure subprocesses capture the correct return code. (first fixed release: 0.13.3).
- 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.3 in real deployments (not just unit tests).
- UvicornWorker does not reset signals correctly, causing issues with log rotation
- Production symptom (often without a traceback): -rw-r--r--. 1 root root 5402 Dec 16 17:08 error.log
Proof / Evidence
- GitHub issue: #896
- Fix PR: https://github.com/encode/uvicorn/pull/895
- First fixed release: 0.13.3
- 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.57
Verified Execution
We executed the runnable minimal repro in a temporary environment and captured exit codes + logs.
- Status: PASS
- Ran: 2026-02-11T16:52:29Z
- Package: uvicorn
- Fixed: 0.13.3
- Mode: fixed_only
- Outcome: ok
Logs
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“> How can we reopen a log file without restarting worker processes for log rotation? no idea, someone more familiar with gunicorn internals might have…”
“logrotate copytruncate option works for me!”
“But use copytruncate instead of create for logrotate, has the risk of lost log record, hope someone can find the real reason cause this issue!”
“In gunicorn(version 20.0.4 ), has some code related to USR1 singles, here is the key code: venv/Lib/site-packages/gunicorn/workers/base.py line 165 venv/Lib/site-packages/gunicorn/glogging.py line 352”
Failure Signature (Search String)
- this 10 times does not log to any access log.
Copy-friendly signature
Failure Signature
-----------------
-rw-r--r--. 1 root root 5402 Dec 16 17:08 error.log
this 10 times does not log to any access log.
Error Message
Signature-only (no traceback captured)
Error Message
-------------
-rw-r--r--. 1 root root 5402 Dec 16 17:08 error.log
this 10 times does not log to any access log.
Minimal Reproduction
import logging
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
logging.basicConfig(level=logging.DEBUG, filename='./log.txt')
logger = logging.getLogger(__name__)
async def some_startup_task():
logger.info("startup")
async def some_shutdown_task():
logger.info("shutdown")
async def homepage(request):
logger.debug("homepage()")
return JSONResponse({'hello': 'world'})
app = Starlette(debug=False,
routes=[Route('/', homepage)],
on_startup=[some_startup_task],
on_shutdown=[some_shutdown_task])
Environment
- Python: 3.8.3
What Broke
Access logs are not written after logrotate is executed, leading to missing log entries.
Why It Broke
UvicornWorker does not reset signals correctly, causing issues with log rotation
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.13.3 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Fix reference: https://github.com/encode/uvicorn/pull/895
First fixed release: 0.13.3
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- Do not use if it changes public behavior or if the failure cannot be reproduced.
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.
Version Compatibility Table
| Version | Status |
|---|---|
| 0.13.3 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.