{"record":{"id":"85ca3b9559ca29e4","repo":"geektutu/7days-golang","slug":"server-returned-v-85ca3b","errorCode":null,"errorMessage":"server returned: %v","messagePattern":"server returned: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-cache/day6-single-flight/geecache/http.go","lineNumber":117,"sourceCode":"type httpGetter struct {\n\tbaseURL string\n}\n\nfunc (h *httpGetter) Get(group string, key string) ([]byte, error) {\n\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":99,"sourceCodeEnd":129,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day6-single-flight/geecache/http.go#L99-L129","documentation":"Same peer-status check as day5, in the day6-single-flight build: httpGetter.Get returns \"server returned: %v\" when a peer node responds with a non-200 status. In this version the error surfaces from within the single-flight group, so all callers waiting on the same key receive the same error for one failed peer request.","triggerScenarios":"group.Get routed via consistent hashing to a peer returning 4xx/5xx; single-flight collapses N concurrent requests onto one failing peer HTTP call, so many callers get this error at once.","commonSituations":"Peer registered with wrong port/path (404); peer overloaded returning 500; peer down behind a proxy returning 502/503; all requests for one hot key fail together because of single-flight fan-in.","solutions":["Read the status from the error and inspect the peer node's logs","Fix peer registration (address + basePath) to match the running server","Restart or repair the unhealthy peer; verify its loader dependencies","Consider per-call fallback to the local loader when peer fetch fails"],"exampleFix":"// before\n// peer fails -> all single-flight waiters get \"server returned: 500\"\nv, err := g.Get(key)\n// after\nv, err := g.Get(key)\nif err != nil {\n    log.Printf(\"peer fetch failed for %q: %v, loading locally\", key, err)\n    return g.loader(key) // fallback to local source\n}","handlingStrategy":"fallback","validationCode":"// verify peer reachability before the ring routes to it\nconn, err := net.DialTimeout(\"tcp\", peerHost, 2*time.Second)\nif err != nil {\n    log.Printf(\"peer %s unreachable, excluding from ring\", peerHost)\n}","typeGuard":null,"tryCatchPattern":"v, err := group.Get(key)\nif err != nil && strings.Contains(err.Error(), \"server returned:\") {\n    log.Printf(\"peer error: %v; falling back to local loader\", err)\n    return g.reloadFromSource(key) // local Getter instead of failing all waiters\n}","preventionTips":["Keep peer versions and endpoints in sync with the ring configuration","Single-flight fans one peer failure out to all waiters — add a local-loader fallback","Monitor per-peer status codes and evict persistently failing peers","Restart/replace unhealthy peers promptly; check their loader dependencies"],"tags":["network","http","distributed-cache","singleflight","go"],"backgroundTag":"http-5xx-response","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"}