The Fix
Upgrade to version 0.17.6 or later.
Based on closed Kludex/uvicorn issue #1286 · PR/commit linked
Production note: This tends to surface only under concurrency. Reproduce with load tests and watch for lock contention/cancellation paths.
@@ -1,10 +1,13 @@
@@ -1,10 +1,13 @@
import ssl
+from copy import deepcopy
import pytest
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-uvicorn-0.16.0-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-uvicorn-0.16.0-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-0.13.1
benchmark: 3.4.1 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
Using --randomly-seed=3526222027
rootdir: /home/tkloczko/rpmbuild/BUILD/uvicorn-0.16.0, configfile: setup.cfg
plugins: shutil-1.7.0, virtualenv-1.7.0, mock-3.6.1, cov-2.12.1, anyio-3.3.4, forked-1.3.0, xdist-2.3.0, flaky-3.7.0, tornasync-0.6.0.post2, console-scripts-1.2.0, trio-0.7.0, timeout-2.0.1, asyncio-0.16.0, freezegun-0.4.2, flake8-1.0.7, pyfakefs-4.5.3, hypothesis-6.29.3, benchmark-3.4.1, profiling-1.7.0, datadir-1.3.1, regressions-2.2.0, randomly-3.8.0, rerunfailures-9.1.1, yagot-0.5.0, requests-mock-1.9.3, subtests-0.5.0, easy-server-0.8.0, django-4.5.2
collected 272 items
tests/middleware/test_proxy_headers.py ........... [ 4%]
tests/test_cli.py ........... [ 8%]
tests/test_ssl.py .... [ 9%]
tests/middleware/test_message_logger.py .. [ 10%]
tests/importer/test_importer.py ...... [ 12%]
tests/test_lifespan.py ............... [ 18%]
tests/test_auto_detection.py ... [ 19%]
tests/middleware/test_logging.py ..........F [ 23%]
tests/test_default_headers.py ...... [ 25%]
tests/test_main.py .F...... [ 28%]
tests/protocols/test_http.py ............................................ [ 44%]
tests/supervisors/test_multiprocess.py . [ 44%]
tests/middleware/test_wsgi.py ..... [ 46%]
tests/protocols/test_utils.py ......
... (truncated) ...
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.17.6 or later.\nWhen NOT to use: This fix is not applicable if the test suite does not depend on the order of tests.\n\nOption C — Workaround\nuse `pytest -p no:randomly`\nWhen NOT to use: This fix is not applicable if the test suite does not depend on the order of tests.\n\n
Why This Fix Works in Production
- Trigger: AttributeError: 'Server' object has no attribute 'servers'
- Mechanism: The pytest test suite depends on the order of parameterized tests, causing random failures
- Why the fix works: Fix logging tests that depend on each other to avoid failures due to the order of parameterized tests. (first fixed release: 0.17.6).
- If left unfixed, failures can be intermittent under concurrency (hard to reproduce; shows up as sporadic 5xx/timeouts).
Why This Breaks in Prod
- Shows up under Python 3.8 in real deployments (not just unit tests).
- The pytest test suite depends on the order of parameterized tests, causing random failures
- Surfaces as: AttributeError: 'Server' object has no attribute 'servers'
Proof / Evidence
- GitHub issue: #1286
- Fix PR: https://github.com/kludex/uvicorn/pull/1291
- First fixed release: 0.17.6
- 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.46
Discussion
High-signal excerpts from the issue thread (symptoms, repros, edge-cases).
“no it's just a way for me to reproduce without pytest-randomly, a fix comes soon”
“Looks like random sufling units is causenig that sometimes pytest is completly frozen and cannot finish.”
“Agreed there is a bug in our test suite, can trigger without pytest-randomly just changing the order of the parametrized tests in test_log_config_default”
“Do you want me to to test that patch? :)”
Failure Signature (Search String)
- AttributeError: 'Server' object has no attribute 'servers'
Error Message
Stack trace
Error Message
-------------
AttributeError: 'Server' object has no attribute 'servers'
Minimal Reproduction
+ PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-uvicorn-0.16.0-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-uvicorn-0.16.0-2.fc35.x86_64/usr/lib/python3.8/site-packages
+ /usr/bin/pytest -ra
=========================================================================== test session starts ============================================================================
platform linux -- Python 3.8.12, pytest-6.2.5, py-1.11.0, pluggy-0.13.1
benchmark: 3.4.1 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
Using --randomly-seed=3526222027
rootdir: /home/tkloczko/rpmbuild/BUILD/uvicorn-0.16.0, configfile: setup.cfg
plugins: shutil-1.7.0, virtualenv-1.7.0, mock-3.6.1, cov-2.12.1, anyio-3.3.4, forked-1.3.0, xdist-2.3.0, flaky-3.7.0, tornasync-0.6.0.post2, console-scripts-1.2.0, trio-0.7.0, timeout-2.0.1, asyncio-0.16.0, freezegun-0.4.2, flake8-1.0.7, pyfakefs-4.5.3, hypothesis-6.29.3, benchmark-3.4.1, profiling-1.7.0, datadir-1.3.1, regressions-2.2.0, randomly-3.8.0, rerunfailures-9.1.1, yagot-0.5.0, requests-mock-1.9.3, subtests-0.5.0, easy-server-0.8.0, django-4.5.2
collected 272 items
tests/middleware/test_proxy_headers.py ........... [ 4%]
tests/test_cli.py ........... [ 8%]
tests/test_ssl.py .... [ 9%]
tests/middleware/test_message_logger.py .. [ 10%]
tests/importer/test_importer.py ...... [ 12%]
tests/test_lifespan.py ............... [ 18%]
tests/test_auto_detection.py ... [ 19%]
tests/middleware/test_logging.py ..........F [ 23%]
tests/test_default_headers.py ...... [ 25%]
tests/test_main.py .F...... [ 28%]
tests/protocols/test_http.py ............................................ [ 44%]
tests/supervisors/test_multiprocess.py . [ 44%]
tests/middleware/test_wsgi.py ..... [ 46%]
tests/protocols/test_utils.py ......
... (truncated) ...
Environment
- Python: 3.8
What Broke
Tests intermittently fail or freeze during execution, leading to unreliable test results.
Why It Broke
The pytest test suite depends on the order of parameterized tests, causing random failures
Fix Options (Details)
Option A — Upgrade to fixed release Safe default (recommended)
Upgrade to version 0.17.6 or later.
Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.
Option C — Workaround Temporary workaround
use `pytest -p no:randomly`
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/1291
First fixed release: 0.17.6
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix is not applicable if the test suite does not depend on the order of tests.
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
- Add a TLS smoke test that performs a real handshake in CI (include CA bundle validation and hostname checks).
- Alert on handshake failures by error string and endpoint to catch cert/CA changes quickly.
- Add a stress test that runs high-concurrency workloads and fails on thread dumps / blocked locks.
- Enable watchdog dumps in prod (faulthandler, thread dump endpoint) to capture deadlocks quickly.
Version Compatibility Table
| Version | Status |
|---|---|
| 0.17.6 | Fixed |
Related Issues
No related fixes found.
Sources
We don’t republish the full GitHub discussion text. Use the links above for context.