From 3b818dcd97e5a9f05a9338baa4ea6a92f2fb000e Mon Sep 17 00:00:00 2001 From: serversdown Date: Tue, 9 Jun 2026 19:12:34 +0000 Subject: [PATCH] fix(slm): stop monitor proxy leaking CancelledError on stream stop The /monitor WS proxy cancelled its sibling task on disconnect but then `except Exception` failed to swallow the resulting CancelledError (a BaseException), so stopping the stream raised "Exception in ASGI application". It also only awaited the pending task, leaving the done task's WebSocketDisconnect unretrieved ("Task exception was never retrieved"). Await all tasks and catch (CancelledError, Exception). Co-Authored-By: Claude Opus 4.8 (1M context) --- backend/routers/slmm.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/routers/slmm.py b/backend/routers/slmm.py index b7d3e48..62a0385 100644 --- a/backend/routers/slmm.py +++ b/backend/routers/slmm.py @@ -269,10 +269,15 @@ async def proxy_websocket_monitor(websocket: WebSocket, unit_id: str): done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) for t in pending: t.cancel() - for t in pending: + # Await ALL tasks (the done one AND the cancelled one) and swallow both + # the expected WebSocketDisconnect and CancelledError. CancelledError is a + # BaseException, so a bare `except Exception` misses it — that's what leaked + # the traceback on stop; and awaiting only `pending` left the done task's + # exception unretrieved. + for t in tasks: try: await t - except Exception: + except (asyncio.CancelledError, Exception): pass except websockets.exceptions.WebSocketException as e: