Jump to solution
Verify

The Fix

Upgrade to version 0.13.3 or later.

Based on closed Kludex/uvicorn issue #920 · PR/commit linked

Jump to Verify Open PR/Commit
@@ -135,6 +135,9 @@ def send_500_response(self): ] self.transport.write(b"".join(content)) + # Allow handler task to terminate cleanly, as websockets doesn't cancel it by + # itself (see https://github.com/encode/uvicorn/issues/920) + self.handshake_started_event.set()
repro.py
$ pytest -k test_missing_handshake ====================================================== test session starts ======================================================= platform darwin -- Python 3.9.0, pytest-6.1.1, py-1.9.0, pluggy-0.13.1 rootdir: /Users/florimond/Developer/python-projects/uvicorn, configfile: setup.cfg plugins: mock-3.3.1, asyncio-0.14.0 collected 213 items / 211 deselected / 2 selected tests/protocols/test_websocket.py .. [100%] =============================================== 2 passed, 211 deselected in 2.30s ================================================ Task was destroyed but it is pending! task: <Task pending name='Task-11' coro=<WebSocketServerProtocol.handler() done, defined at /Users/florimond/Developer/python-projects/uvicorn/venv/lib/python3.9/site-packages/websockets/server.py:118> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x10a7e1760>()]>>
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
Option A — Upgrade to fixed release\nUpgrade to version 0.13.3 or later.\nWhen NOT to use: Do not apply this fix if the websocket implementation does not handle handshake failures.\n\n

Why This Fix Works in Production

  • Trigger: Websockets implementation does not clean properly tasks if handshake fails
  • Mechanism: Handshake failures in the websockets implementation leave tasks pending
  • Why the fix works: Fixes the websockets implementation where handshake failures leave tasks pending. (first fixed release: 0.13.3).

Why This Breaks in Prod

  • Shows up under Python 3.9.0 in real deployments (not just unit tests).
  • Handshake failures in the websockets implementation leave tasks pending
  • Production symptom (often without a traceback): Websockets implementation does not clean properly tasks if handshake fails

Proof / Evidence

  • GitHub issue: #920
  • Fix PR: https://github.com/kludex/uvicorn/pull/921
  • 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.42

Discussion

High-signal excerpts from the issue thread (symptoms, repros, edge-cases).

“this is a good explanation of what we see in those 2 tests and that causes flaky tests: FWIW there's an asyncio warning when I try to run test_send_before_handshake or test_missing_handshake in isolation. Doesn't show if I run either along”
Issue thread · issue description · source

Failure Signature (Search String)

  • Websockets implementation does not clean properly tasks if handshake fails
Copy-friendly signature
signature.txt
Failure Signature ----------------- Websockets implementation does not clean properly tasks if handshake fails $ pytest -k test_missing_handshake

Error Message

Signature-only (no traceback captured)
error.txt
Error Message ------------- Websockets implementation does not clean properly tasks if handshake fails $ pytest -k test_missing_handshake

Minimal Reproduction

repro.py
$ pytest -k test_missing_handshake ====================================================== test session starts ======================================================= platform darwin -- Python 3.9.0, pytest-6.1.1, py-1.9.0, pluggy-0.13.1 rootdir: /Users/florimond/Developer/python-projects/uvicorn, configfile: setup.cfg plugins: mock-3.3.1, asyncio-0.14.0 collected 213 items / 211 deselected / 2 selected tests/protocols/test_websocket.py .. [100%] =============================================== 2 passed, 211 deselected in 2.30s ================================================ Task was destroyed but it is pending! task: <Task pending name='Task-11' coro=<WebSocketServerProtocol.handler() done, defined at /Users/florimond/Developer/python-projects/uvicorn/venv/lib/python3.9/site-packages/websockets/server.py:118> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x10a7e1760>()]>>

Environment

  • Python: 3.9.0

What Broke

Flaky tests due to pending tasks causing warnings and inconsistent test results.

Why It Broke

Handshake failures in the websockets implementation leave tasks pending

Fix Options (Details)

Option A — Upgrade to fixed release Safe default (recommended)

Upgrade to version 0.13.3 or later.

When NOT to use: Do not apply this fix if the websocket implementation does not handle handshake failures.

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/921

First fixed release: 0.13.3

Last verified: 2026-02-09. Validate in your environment.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • Do not apply this fix if the websocket implementation does not handle handshake failures.

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

  • 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.

Version Compatibility Table

VersionStatus
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.