{"record":{"id":"add187a3a0adc090","repo":"chenhg5/cc-connect","slug":"read-response-body-w","errorCode":null,"errorMessage":"read response body: %w","messagePattern":"read response body: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/slack/slack.go","lineNumber":582,"sourceCode":"\t\treturn nil, fmt.Errorf(\"empty URL\")\n\t}\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\treq.Header.Set(\"Authorization\", \"Bearer \"+p.botToken)\n\tresp, err := core.HTTPClient.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%s\", core.RedactToken(err.Error(), p.botToken))\n\t}\n\tdefer resp.Body.Close()\n\n\t// Check if we got an unexpected status code (e.g., redirect to login page)\n\tif resp.StatusCode != http.StatusOK {\n\t\tbody, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))\n\t\treturn nil, fmt.Errorf(\"download failed with status %d: %s\", resp.StatusCode, string(body))\n\t}\n\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read response body: %w\", err)\n\t}\n\n\t// Basic sanity check: detect if we received HTML instead of binary data\n\tif len(data) > 0 && (bytes.HasPrefix(data, []byte(\"<!DOCTYPE\")) || bytes.HasPrefix(data, []byte(\"<html\"))) {\n\t\treturn nil, fmt.Errorf(\"received HTML response (likely missing auth); first 100 bytes: %s\", string(data[:min(100, len(data))]))\n\t}\n\n\treturn data, nil\n}\n\nfunc (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {\n\t// slack:{channel}:{user}  |  slack:{channel}:t:{threadTS}  |  slack:{channel}\n\tparts := strings.SplitN(sessionKey, \":\", 3)\n\tif len(parts) < 2 || parts[0] != \"slack\" {\n\t\treturn nil, fmt.Errorf(\"slack: invalid session key %q\", sessionKey)\n\t}\n\trc := replyContext{channel: parts[1]}\n\t// Thread-scoped keys carry the thread root ts as a \"t:<ts>\" suffix; preserve","sourceCodeStart":564,"sourceCodeEnd":600,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/slack/slack.go#L564-L600","documentation":"downloadSlackFile fetches a Slack file via its private/public URL and reads the full response body with io.ReadAll. This error wraps any transient I/O failure that occurs while streaming the body (connection reset, timeout, context cancellation mid-read). It indicates the download failed partway through after a successful HTTP 200.","triggerScenarios":"resp.Body read fails inside downloadSlackFile after the status-200 check — e.g. server closes the connection mid-transfer, network drops, or the request context is cancelled while reading.","commonSituations":"Large Slack file downloads over flaky networks; Slack CDN closing idle connections; bot shutdown cancelling the context during processSlackFileShares; proxy/VPN interruptions.","solutions":["Retry downloadSlackFile with backoff; body-read failures are usually transient","Check network connectivity / proxy configuration between the host and Slack CDN","Ensure the context passed down is not being cancelled prematurely (e.g. short engine timeout)","Log the wrapped error to identify whether it is a timeout, reset, or cancellation"],"exampleFix":"// before\ndata, err := io.ReadAll(resp.Body)\nif err != nil {\n    return nil, fmt.Errorf(\"read response body: %w\", err)\n}\n// after\ndata, err := io.ReadAll(resp.Body)\nif err != nil {\n    return nil, fmt.Errorf(\"read response body: %w\", err) // caller should retry with backoff\n}","handlingStrategy":"retry","validationCode":"// pre-check not possible for mid-read failure; instead bound it:\nctx, cancel := context.WithTimeout(ctx, 30*time.Second)\ndefer cancel()\nreq = req.WithContext(ctx)","typeGuard":null,"tryCatchPattern":"data, err := downloadSlackFile(url, token)\nif err != nil {\n    if strings.Contains(err.Error(), \"read response body\") {\n        // transient: retry with backoff\n    }\n    return fmt.Errorf(\"process file share: %w\", err)\n}","preventionTips":["Always pass a context with a sane timeout to downloads","Retry transient body-read failures with exponential backoff","Monitor network stability between host and Slack CDN"],"tags":["network","slack","file-download","io"],"backgroundTag":"http-request-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}