geektutu/7days-golang · error
reading response body: %v
Error message
reading response body: %v
What it means
After a 200 OK response is received from a peer node, httpGetter reads the entire response body with ioutil.ReadAll. If that read fails — connection reset mid-response, deadline exceeded, truncated transfer — the underlying I/O error is wrapped as "reading response body: %v". This indicates the network connection broke after the headers arrived.
Source
Thrown at gee-cache/day5-multi-nodes/geecache/http.go:122
u := fmt.Sprintf(
"%v%v/%v",
h.baseURL,
url.QueryEscape(group),
url.QueryEscape(key),
)
res, err := http.Get(u)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("server returned: %v", res.Status)
}
bytes, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("reading response body: %v", err)
}
return bytes, nil
}
var _ PeerGetter = (*httpGetter)(nil)
View on GitHub (pinned to cf36443821)
Solutions
- Retry the request — transient truncation often succeeds on a second attempt
- Increase or correctly configure the http.Client timeout used for peer fetches
- Check network stability between nodes (LB idle timeouts, NAT, keep-alive settings)
- Log the wrapped underlying error to confirm whether it's a timeout vs connection reset
Example fix
// before
client := &http.Client{} // no timeout, defaults vary
// after
client := &http.Client{Timeout: 5 * time.Second}
// and on the caller:
v, err := group.Get(key)
if err != nil {
if isTransient(err) { return retry(key) }
return err
} Defensive patterns
Strategy: retry
Validate before calling
client := &http.Client{Timeout: 5 * time.Second} // set before use
// wrap: cancel early if caller context is already done
if ctx.Err() != nil {
return ctx.Err()
} Try / catch
v, err := group.Get(key)
if err != nil && strings.Contains(err.Error(), "reading response body") {
// transient truncation: retry once with backoff
time.Sleep(50 * time.Millisecond)
return group.Get(key)
} Prevention
- Set explicit http.Client timeouts instead of relying on defaults
- Raise LB/proxy idle timeouts above your largest expected response time
- Enable keep-alives and reuse connections between cache nodes
- Alert on truncated-response errors to catch network degradation early
When it happens
Trigger: Calling group.Get(key) routed to a peer whose connection drops while the body is being transferred; client-side http.Client timeout elapsing mid-body; peer process killed after sending headers.
Common situations: Flaky network between nodes (containers/k8s pod restarts); load balancer idle-timeout closing slow responses; overly short client timeout configured on http.Client used by the peer pool; very large cache values slow to transfer.
Related errors
- reading response body: %v
- reading response body: %v
- server returned: %v
- server returned: %v
- server returned: %v
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/ec00e9a5fd0d3440.
Report an issue: GitHub.