The Fix
Fix lifespan tests that were silently failing by correcting the assert scope shape.
Based on closed Kludex/uvicorn issue #911 · PR/commit linked
@@ -146,26 +146,33 @@ async def test():
[email protected]("mode", ("auto", "on"))
-def test_lifespan_scope_asgi3app(mode):
+def test_lifespan_scope_asgi3app():
@pytest.mark.parametrize("mode", ("auto", "on"))
def test_lifespan_scope_asgi3app(mode):
async def asgi3app(scope, receive, send):
assert scope == {"version": "3.0", "spec_version": "2.0"}
async def test():
config = Config(app=asgi3app, lifespan=mode)
lifespan = LifespanOn(config)
await lifespan.startup()
await lifespan.shutdown()
loop = asyncio.new_event_loop()
loop.run_until_complete(test())
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
Option A — Apply the official fix\nFix lifespan tests that were silently failing by correcting the assert scope shape.\nWhen NOT to use: This fix is not applicable if the test assertions are intended to validate different scope shapes.\n\n
Why This Fix Works in Production
- Trigger: Testing started at 2:47 PM ...
- Mechanism: The lifespan tests were incorrectly asserting the shape of the scope dictionary
- If left unfixed, this can cause silent data inconsistencies that propagate (bad cache entries, incorrect downstream decisions).
Why This Breaks in Prod
- Shows up under Python 3.8.5 in real deployments (not just unit tests).
- The lifespan tests were incorrectly asserting the shape of the scope dictionary
- Surfaces as: /home/lotso/PycharmProjects/uvicorn/venv/bin/python /home/lotso/.local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-0/203.5981.165/plugins/python/helpers/pycharm/_jb_pytest_runner.py…
Proof / Evidence
- GitHub issue: #911
- Fix PR: https://github.com/kludex/uvicorn/pull/913
- 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.38
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“### Checklist <!-- Please make sure you check all these items before submitting your bug report. --> - [x] The bug is reproducible against the latest release and/or master. - [x] There are no similar issues or pull requests to fix it yet. #”
Failure Signature (Search String)
- Testing started at 2:47 PM ...
Error Message
Stack trace
Error Message
-------------
/home/lotso/PycharmProjects/uvicorn/venv/bin/python /home/lotso/.local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-0/203.5981.165/plugins/python/helpers/pycharm/_jb_pytest_runner.py --target test_lifespan.py::test_lifespan_scope_asgi3app
Testing started at 2:47 PM ...
Launching pytest with arguments test_lifespan.py::test_lifespan_scope_asgi3app in /home/lotso/PycharmProjects/uvicorn/tests
============================= test session starts ==============================
platform linux -- Python 3.8.5, pytest-6.2.0, py-1.10.0, pluggy-0.13.1 -- /home/lotso/PycharmProjects/uvicorn/venv/bin/python
cachedir: .pytest_cache
rootdir: /home/lotso/PycharmProjects/uvicorn, configfile: setup.cfg
plugins: reraise-1.0.3, asyncio-0.14.0
collecting ... collected 2 items
test_lifespan.py::test_lifespan_scope_asgi3app[auto]
test_lifespan.py::test_lifespan_scope_asgi3app[on]
============================== 2 passed in 0.11s ===============================
Process finished with exit code 0
PASSED [ 50%]INFO: Waiting for application startup.
INFO: ASGI 'lifespan' protocol appears unsupported.
INFO: Application startup complete.
PASSED [100%]INFO: Waiting for application startup.
ERROR: Exception in 'lifespan' protocol
Traceback (most recent call last):
File "/home/lotso/PycharmProjects/uvicorn/uvicorn/lifespan/on.py", line 55, in main
await app
... (truncated) ...
Minimal Reproduction
@pytest.mark.parametrize("mode", ("auto", "on"))
def test_lifespan_scope_asgi3app(mode):
async def asgi3app(scope, receive, send):
assert scope == {"version": "3.0", "spec_version": "2.0"}
async def test():
config = Config(app=asgi3app, lifespan=mode)
lifespan = LifespanOn(config)
await lifespan.startup()
await lifespan.shutdown()
loop = asyncio.new_event_loop()
loop.run_until_complete(test())
Environment
- Python: 3.8.5
What Broke
Lifespan tests passed when they should have failed, leading to false positives in test results.
Why It Broke
The lifespan tests were incorrectly asserting the shape of the scope dictionary
Fix Options (Details)
Option A — Apply the official fix
Fix lifespan tests that were silently failing by correcting the assert scope shape.
Fix reference: https://github.com/kludex/uvicorn/pull/913
Last verified: 2026-02-12. Validate in your environment.
When NOT to Use This Fix
- This fix is not applicable if the test assertions are intended to validate different scope shapes.
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.