From 57f249a89dc87ec3541da325bbd299b4ff96cefb Mon Sep 17 00:00:00 2001 From: viettranx Date: Mon, 23 Mar 2026 12:11:47 +0700 Subject: [PATCH] fix(gateway): prevent panic on send to closed WebSocket client channel Agent run goroutines can outlive the WebSocket client (e.g. after reconnect). When the goroutine finishes and calls SendResponse/SendEvent, the closed send channel causes a panic that crashes the server. Add defer/recover to both methods to gracefully drop messages for disconnected clients instead of panicking. --- internal/gateway/client.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/internal/gateway/client.go b/internal/gateway/client.go index 837e338f..f9d9744c 100644 --- a/internal/gateway/client.go +++ b/internal/gateway/client.go @@ -160,6 +160,11 @@ func (c *Client) SendResponse(resp *protocol.ResponseFrame) { slog.Error("marshal response failed", "error", err) return } + defer func() { + if r := recover(); r != nil { + slog.Debug("client gone, dropping response", "client", c.id) + } + }() select { case c.send <- data: default: @@ -174,6 +179,11 @@ func (c *Client) SendEvent(event protocol.EventFrame) { slog.Error("marshal event failed", "error", err) return } + defer func() { + if r := recover(); r != nil { + slog.Debug("client gone, dropping event", "client", c.id) + } + }() select { case c.send <- data: default: