geektutu/7days-golang · error

reading response body: %v

Error message

reading response body: %v

What it means

In the day7 build, after a 200 response from a peer, the body bytes are read and then handed to the caller; an ioutil.ReadAll failure is wrapped as "reading response body: %v". The proto decoding has its own separate error, so this one strictly indicates an I/O problem while streaming the body.

Source

Thrown at gee-cache/day7-proto-buf/geecache/http.go:132

	u := fmt.Sprintf(
		"%v%v/%v",
		h.baseURL,
		url.QueryEscape(in.GetGroup()),
		url.QueryEscape(in.GetKey()),
	)
	res, err := http.Get(u)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != http.StatusOK {
		return fmt.Errorf("server returned: %v", res.Status)
	}

	bytes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return fmt.Errorf("reading response body: %v", err)
	}

	if err = proto.Unmarshal(bytes, out); err != nil {
		return fmt.Errorf("decoding response body: %v", err)
	}

	return nil
}

var _ PeerGetter = (*httpGetter)(nil)

View on GitHub (pinned to cf36443821)

Solutions

  1. Retry the peer fetch (single-flight will coalesce concurrent retries)
  2. Configure a sane http.Client.Timeout on the peer client
  3. Inspect the wrapped error (timeout vs reset) and adjust the responsible layer (LB, proxy, keep-alives)
  4. Check peer health/memory if responses are being cut off consistently

Example fix

// before
client := &http.Client{}
bytes, err := ioutil.ReadAll(res.Body)
// after
client := &http.Client{Timeout: 5 * time.Second}
bytes, err := io.ReadAll(res.Body)
if err != nil {
    return fmt.Errorf("reading response body (peer %s): %w", peerAddr, err)
}
Defensive patterns

Strategy: retry

Validate before calling

client := &http.Client{Timeout: 5 * time.Second}
if res.ContentLength == 0 {
    return errors.New("empty peer response")
}

Try / catch

err := g.Get(ctx, key, &out)
if err != nil && strings.Contains(err.Error(), "reading response body") {
    // transient I/O failure mid-body: retry once
    return g.Get(ctx, key, &out)
}

Prevention

When it happens

Trigger: Peer connection reset or closed after headers during a protobuf response transfer; client timeout expiring mid-read; intermediary dropping the response.

Common situations: Unstable inter-node networks; pod restarts mid-response; undersized client timeouts under load; large values slow to serialize/transfer.

Related errors


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