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

  1. Retry the request — transient truncation often succeeds on a second attempt
  2. Increase or correctly configure the http.Client timeout used for peer fetches
  3. Check network stability between nodes (LB idle timeouts, NAT, keep-alive settings)
  4. 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

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


AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03). Data as JSON: /api/errors/ec00e9a5fd0d3440. Report an issue: GitHub.