{"record":{"id":"c130bc5de1afb1b8","repo":"geektutu/7days-golang","slug":"reading-response-body-v-c130bc","errorCode":null,"errorMessage":"reading response body: %v","messagePattern":"reading response body: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-cache/day7-proto-buf/geecache/http.go","lineNumber":132,"sourceCode":"\tu := fmt.Sprintf(\n\t\t\"%v%v/%v\",\n\t\th.baseURL,\n\t\turl.QueryEscape(in.GetGroup()),\n\t\turl.QueryEscape(in.GetKey()),\n\t)\n\tres, err := http.Get(u)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer res.Body.Close()\n\n\tif res.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"server returned: %v\", res.Status)\n\t}\n\n\tbytes, err := ioutil.ReadAll(res.Body)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"reading response body: %v\", err)\n\t}\n\n\tif err = proto.Unmarshal(bytes, out); err != nil {\n\t\treturn fmt.Errorf(\"decoding response body: %v\", err)\n\t}\n\n\treturn nil\n}\n\nvar _ PeerGetter = (*httpGetter)(nil)\n","sourceCodeStart":114,"sourceCodeEnd":143,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day7-proto-buf/geecache/http.go#L114-L143","documentation":"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.","triggerScenarios":"Peer connection reset or closed after headers during a protobuf response transfer; client timeout expiring mid-read; intermediary dropping the response.","commonSituations":"Unstable inter-node networks; pod restarts mid-response; undersized client timeouts under load; large values slow to serialize/transfer.","solutions":["Retry the peer fetch (single-flight will coalesce concurrent retries)","Configure a sane http.Client.Timeout on the peer client","Inspect the wrapped error (timeout vs reset) and adjust the responsible layer (LB, proxy, keep-alives)","Check peer health/memory if responses are being cut off consistently"],"exampleFix":"// before\nclient := &http.Client{}\nbytes, err := ioutil.ReadAll(res.Body)\n// after\nclient := &http.Client{Timeout: 5 * time.Second}\nbytes, err := io.ReadAll(res.Body)\nif err != nil {\n    return fmt.Errorf(\"reading response body (peer %s): %w\", peerAddr, err)\n}","handlingStrategy":"retry","validationCode":"client := &http.Client{Timeout: 5 * time.Second}\nif res.ContentLength == 0 {\n    return errors.New(\"empty peer response\")\n}","typeGuard":null,"tryCatchPattern":"err := g.Get(ctx, key, &out)\nif err != nil && strings.Contains(err.Error(), \"reading response body\") {\n    // transient I/O failure mid-body: retry once\n    return g.Get(ctx, key, &out)\n}","preventionTips":["Set explicit client timeouts; avoid default transport quirks","Confirm intermediaries don't cut long protobuf responses","Track node restarts/OOMs — they manifest as body-read failures","Include the peer address in your own error wrapping for faster triage"],"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"}