From 7375058d2ca29d35e44e6b6a8ddabedd724428d8 Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Sat, 23 May 2026 08:02:50 +0000 Subject: [PATCH] fix(channels): handle io.ReadAll errors and close body in Slack adapter Three ignored io.ReadAll errors in the Slack adapter were masking network/read failures as success or surfacing misleading error messages: 1. sendBotMessage: a failed read was silently treated as success because json.Unmarshal on empty respBody returns an error, skipping the !result.OK check. Now returns the read error explicitly. 2. sendWebhookMessage: missing resp.Body.Close() caused a resource leak on every call. Added defer close and explicit read-error handling. 3. FetchChannelHistory: ignored read error caused \"slack history API error\" even when the failure was at the transport layer. Now surfaces the read error directly. Co-Authored-By: Claude Opus 4.7 --- workspace-server/internal/channels/slack.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/workspace-server/internal/channels/slack.go b/workspace-server/internal/channels/slack.go index 3bead7d81..511ff3eb5 100644 --- a/workspace-server/internal/channels/slack.go +++ b/workspace-server/internal/channels/slack.go @@ -171,8 +171,11 @@ func (s *SlackAdapter) sendBotMessage(ctx context.Context, config map[string]int if err != nil { return fmt.Errorf("slack: send: %w", err) } - respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 4096)) + respBody, readErr := io.ReadAll(io.LimitReader(resp.Body, 4096)) _ = resp.Body.Close() + if readErr != nil { + return fmt.Errorf("slack: read response body: %w", readErr) + } var result struct { OK bool `json:"ok"` Error string `json:"error"` @@ -208,9 +211,13 @@ func (s *SlackAdapter) sendWebhookMessage(ctx context.Context, config map[string if err != nil { return fmt.Errorf("slack: send: %w", err) } + defer func() { _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { - body, _ := io.ReadAll(resp.Body) + body, readErr := io.ReadAll(resp.Body) + if readErr != nil { + return fmt.Errorf("slack: webhook returned %d (read body failed: %v)", resp.StatusCode, readErr) + } return fmt.Errorf("slack: webhook returned %d: %s", resp.StatusCode, strings.TrimSpace(string(body))) } return nil @@ -524,8 +531,11 @@ func FetchChannelHistory(ctx context.Context, botToken, channelID string, limit if err != nil { return nil, err } - body, _ := io.ReadAll(io.LimitReader(resp.Body, 65536)) + body, readErr := io.ReadAll(io.LimitReader(resp.Body, 65536)) _ = resp.Body.Close() + if readErr != nil { + return nil, fmt.Errorf("slack: read history response: %w", readErr) + } var result struct { OK bool `json:"ok"` -- 2.52.0