geektutu/7days-golang · error

reading response body: %v

Error message

reading response body: %v

What it means

The day6-single-flight httpGetter wraps ioutil.ReadAll failures on the peer's 200 response as "reading response body: %v". The connection was established and headers received, but the body stream broke. Because of single-flight, one broken read fails every concurrent caller of that key.

Source

Thrown at gee-cache/day6-single-flight/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 operation — with single-flight the retry collapses into a fresh peer fetch
  2. Set an explicit, adequate http.Client.Timeout for peer requests
  3. Check for intermediary (proxy/LB) response timeouts and raise them
  4. Capture the wrapped cause (context deadline exceeded vs connection reset) to target the fix

Example fix

// before
client := &http.Client{} // unbounded/hanging reads
// after
client := &http.Client{Timeout: 5 * time.Second}
// caller side retry:
var v ByteView
var err error
for i := 0; i < 2 && err != nil; i++ {
    v, err = g.Get(key)
}
Defensive patterns

Strategy: retry

Validate before calling

client := &http.Client{Timeout: 5 * time.Second}
// pre-flight: ensure the request context is still alive
select {
case <-ctx.Done():
    return ctx.Err()
default:
}

Try / catch

v, err := group.Get(key)
if err != nil && strings.Contains(err.Error(), "reading response body") {
    // single-flight collapses concurrent retries; one retry is enough
    time.Sleep(100 * time.Millisecond)
    return group.Get(key)
}

Prevention

When it happens

Trigger: Peer connection reset during body transfer; http.Client timeout firing mid-read; peer killed after sending response headers while N waiters are pinned to the same flight.

Common situations: Pod/OOM kills mid-response in k8s; LB or proxy cutting long responses; too-aggressive client timeouts; unstable network in dev clusters.

Related errors


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