chenhg5/cc-connect · error
read response body: %w
Error message
read response body: %w
What it means
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.
Source
Thrown at platform/slack/slack.go:582
return nil, fmt.Errorf("empty URL")
}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", "Bearer "+p.botToken)
resp, err := core.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("%s", core.RedactToken(err.Error(), p.botToken))
}
defer resp.Body.Close()
// Check if we got an unexpected status code (e.g., redirect to login page)
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
return nil, fmt.Errorf("download failed with status %d: %s", resp.StatusCode, string(body))
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read response body: %w", err)
}
// Basic sanity check: detect if we received HTML instead of binary data
if len(data) > 0 && (bytes.HasPrefix(data, []byte("<!DOCTYPE")) || bytes.HasPrefix(data, []byte("<html"))) {
return nil, fmt.Errorf("received HTML response (likely missing auth); first 100 bytes: %s", string(data[:min(100, len(data))]))
}
return data, nil
}
func (p *Platform) ReconstructReplyCtx(sessionKey string) (any, error) {
// slack:{channel}:{user} | slack:{channel}:t:{threadTS} | slack:{channel}
parts := strings.SplitN(sessionKey, ":", 3)
if len(parts) < 2 || parts[0] != "slack" {
return nil, fmt.Errorf("slack: invalid session key %q", sessionKey)
}
rc := replyContext{channel: parts[1]}
// Thread-scoped keys carry the thread root ts as a "t:<ts>" suffix; preserveView on GitHub (pinned to 4000b2338a)
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
Example fix
// before
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read response body: %w", err)
}
// after
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read response body: %w", err) // caller should retry with backoff
} Defensive patterns
Strategy: retry
Validate before calling
// pre-check not possible for mid-read failure; instead bound it: ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() req = req.WithContext(ctx)
Try / catch
data, err := downloadSlackFile(url, token)
if err != nil {
if strings.Contains(err.Error(), "read response body") {
// transient: retry with backoff
}
return fmt.Errorf("process file share: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Large Slack file downloads over flaky networks; Slack CDN closing idle connections; bot shutdown cancelling the context during processSlackFileShares; proxy/VPN interruptions.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- read body from %s: %w
- read body from %s: %w
- read response: %w
- gemini stt: read response: %w
- qwen tts: read response: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/add187a3a0adc090.
Report an issue: GitHub.