{"record":{"id":"ec00e9a5fd0d3440","repo":"geektutu/7days-golang","slug":"reading-response-body-v","errorCode":null,"errorMessage":"reading response body: %v","messagePattern":"reading response body: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-cache/day5-multi-nodes/geecache/http.go","lineNumber":122,"sourceCode":"\tu := fmt.Sprintf(\n\t\t\"%v%v/%v\",\n\t\th.baseURL,\n\t\turl.QueryEscape(group),\n\t\turl.QueryEscape(key),\n\t)\n\tres, err := http.Get(u)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer res.Body.Close()\n\n\tif res.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"server returned: %v\", res.Status)\n\t}\n\n\tbytes, err := ioutil.ReadAll(res.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading response body: %v\", err)\n\t}\n\n\treturn bytes, nil\n}\n\nvar _ PeerGetter = (*httpGetter)(nil)\n","sourceCodeStart":104,"sourceCodeEnd":129,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day5-multi-nodes/geecache/http.go#L104-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nclient := &http.Client{} // no timeout, defaults vary\n// after\nclient := &http.Client{Timeout: 5 * time.Second}\n// and on the caller:\nv, err := group.Get(key)\nif err != nil {\n    if isTransient(err) { return retry(key) }\n    return err\n}","handlingStrategy":"retry","validationCode":"client := &http.Client{Timeout: 5 * time.Second} // set before use\n// wrap: cancel early if caller context is already done\nif ctx.Err() != nil {\n    return ctx.Err()\n}","typeGuard":null,"tryCatchPattern":"v, err := group.Get(key)\nif err != nil && strings.Contains(err.Error(), \"reading response body\") {\n    // transient truncation: retry once with backoff\n    time.Sleep(50 * time.Millisecond)\n    return group.Get(key)\n}","preventionTips":["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"],"tags":["network","http","io","distributed-cache","go"],"backgroundTag":"response-body-read-failed","analyzedSha":"cf3644382101dc13e7fd92e8f5c66cabc51bcd3b","analyzedAt":"2026-09-03T18:31:24.087Z","contentChangedAt":"2026-09-03T18:31:24.087Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}