The Fix
Upgrade to version 0.23.0 or later.
Based on closed Kludex/uvicorn issue #1958 · 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%.
@@ -5,6 +5,7 @@
import typing
from pathlib import Path
+from typing import Optional
from unittest.mock import MagicMock
import uvicorn
async def app(scope, receive, send):
assert scope['type'] == 'http'
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
],
})
await send({
'type': 'http.response.body',
'body': b'Hello, world!',
})
if __name__ == "__main__":
LOG_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"simple": {
"format": "[%(levelname)s] %(message)s",
},
},
"handlers": {
"stdout": {
"level": "NOTSET",
"class": "logging.StreamHandler",
"formatter": "simple",
"stream": "ext://sys.stdout",
}
},
"root": {
"handlers": ["stdout"],
"level": "WARNING",
},
"loggers": {
"uvicorn": {
"handlers": ["stdout"],
"level": "INFO",
"propagate": False,
},
},
}
uvicorn.run("main:app", log_config=LOG_CONFIG)
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.23.0 or later.\nWhen NOT to use: This fix is not applicable if the logger's effective level is intentionally set to a higher threshold.\n\n
Why This Fix Works in Production
- Trigger: So what I think is that on that line, `logger.level` should be changed to `logger.getEffectiveLevel()`.
- Mechanism: Changes the logger level check to use logger.getEffectiveLevel() instead of logger.level, ensuring the correct logging level is respected.
- Why the fix works: Changes the logger level check to use logger.getEffectiveLevel() instead of logger.level, ensuring the correct logging level is respected. (first fixed release: 0.23.0).
- 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
- Production symptom (often without a traceback): So what I think is that on that line, `logger.level` should be changed to `logger.getEffectiveLevel()`.
Proof / Evidence
- GitHub issue: #1958
- Fix PR: https://github.com/kludex/uvicorn/pull/1966
- First fixed release: 0.23.0
- 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.42
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“Can you give an MRE on which the change will benefit you?”
“Got it. Thanks. Do you mind creating a PR for it? 🙏”
“Hey, see here an example: I'm setting uvicorn logger to log on level INFO, so every child logger (uvicorn.error, uvicorn.access, uvicorn.asgi, etc) will use that…”
Failure Signature (Search String)
- So what I think is that on that line, `logger.level` should be changed to `logger.getEffectiveLevel()`.
- Sorry if I'm missing something and thanks for taking care of this project.
Copy-friendly signature
Failure Signature
-----------------
So what I think is that on that line, `logger.level` should be changed to `logger.getEffectiveLevel()`.
Sorry if I'm missing something and thanks for taking care of this project.
Error Message
Signature-only (no traceback captured)
Error Message
-------------
So what I think is that on that line, `logger.level` should be changed to `logger.getEffectiveLevel()`.
Sorry if I'm missing something and thanks for taking care of this project.
Minimal Reproduction
import uvicorn
async def app(scope, receive, send):
assert scope['type'] == 'http'
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
],
})
await send({
'type': 'http.response.body',
'body': b'Hello, world!',
})
if __name__ == "__main__":
LOG_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"simple": {
"format": "[%(levelname)s] %(message)s",
},
},
"handlers": {
"stdout": {
"level": "NOTSET",
"class": "logging.StreamHandler",
"formatter": "simple",
"stream": "ext://sys.stdout",
}
},
"root": {
"handlers": ["stdout"],
"level": "WARNING",
},
"loggers": {
"uvicorn": {
"handlers": ["stdout"],
"level": "INFO",
"propagate": False,
},
},
}
uvicorn.run("main:app", log_config=LOG_CONFIG)
What Broke
Logs were not captured at the expected level, causing confusion during application runtime.
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.23.0 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Fix reference: https://github.com/kludex/uvicorn/pull/1966
First fixed release: 0.23.0
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix is not applicable if the logger's effective level is intentionally set to a higher threshold.
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.23.0 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.