Jump to solution
Verify

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

Jump to Verify Open PR/Commit
@@ -146,26 +146,33 @@ async def test(): [email protected]("mode", ("auto", "on")) -def test_lifespan_scope_asgi3app(mode): +def test_lifespan_scope_asgi3app():
repro.py
@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())
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\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
Production impact:
  • 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

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. #”
Issue thread · issue description · source

Failure Signature (Search String)

  • Testing started at 2:47 PM ...

Error Message

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

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

When NOT to use: This fix is not applicable if the test assertions are intended to validate different scope shapes.

Fix reference: https://github.com/kludex/uvicorn/pull/913

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 the test assertions are intended to validate different scope shapes.

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.