{"record":{"id":"952634f7e4f6a670","repo":"geektutu/7days-golang","slug":"reading-response-body-v-952634","errorCode":null,"errorMessage":"reading response body: %v","messagePattern":"reading response body: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-cache/day6-single-flight/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/day6-single-flight/geecache/http.go#L104-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"Pod/OOM kills mid-response in k8s; LB or proxy cutting long responses; too-aggressive client timeouts; unstable network in dev clusters.","solutions":["Retry the operation — with single-flight the retry collapses into a fresh peer fetch","Set an explicit, adequate http.Client.Timeout for peer requests","Check for intermediary (proxy/LB) response timeouts and raise them","Capture the wrapped cause (context deadline exceeded vs connection reset) to target the fix"],"exampleFix":"// before\nclient := &http.Client{} // unbounded/hanging reads\n// after\nclient := &http.Client{Timeout: 5 * time.Second}\n// caller side retry:\nvar v ByteView\nvar err error\nfor i := 0; i < 2 && err != nil; i++ {\n    v, err = g.Get(key)\n}","handlingStrategy":"retry","validationCode":"client := &http.Client{Timeout: 5 * time.Second}\n// pre-flight: ensure the request context is still alive\nselect {\ncase <-ctx.Done():\n    return ctx.Err()\ndefault:\n}","typeGuard":null,"tryCatchPattern":"v, err := group.Get(key)\nif err != nil && strings.Contains(err.Error(), \"reading response body\") {\n    // single-flight collapses concurrent retries; one retry is enough\n    time.Sleep(100 * time.Millisecond)\n    return group.Get(key)\n}","preventionTips":["Use bounded client timeouts so a stuck read fails fast and can retry","Check pod stability (OOM kills cut responses mid-stream) in orchestrated environments","Keep proxy/LB response timeouts comfortably above worst-case peer fetch time","Distinguish timeout vs reset in the wrapped message to target fixes"],"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"}