{"record":{"id":"fc5f1120d82e31f5","repo":"geektutu/7days-golang","slug":"err-error-fc5f11","errorCode":null,"errorMessage":"err.Error()","messagePattern":"err\\.Error\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"gee-cache/day4-consistent-hash/geecache/http.go","lineNumber":56,"sourceCode":"\t// /<basepath>/<groupname>/<key> required\n\tparts := strings.SplitN(r.URL.Path[len(p.basePath):], \"/\", 2)\n\tif len(parts) != 2 {\n\t\thttp.Error(w, \"bad request\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tgroupName := parts[0]\n\tkey := parts[1]\n\n\tgroup := GetGroup(groupName)\n\tif group == nil {\n\t\thttp.Error(w, \"no such group: \"+groupName, http.StatusNotFound)\n\t\treturn\n\t}\n\n\tview, err := group.Get(key)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tw.Header().Set(\"Content-Type\", \"application/octet-stream\")\n\tw.Write(view.ByteSlice())\n}\n","sourceCodeStart":38,"sourceCodeEnd":63,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day4-consistent-hash/geecache/http.go#L38-L63","documentation":"day4 ServeHTTP: the group exists but group.Get(key) returned an error, propagated to the client as HTTP 500 with err.Error(). Typical origin: the GetterFunc failing, or (with consistent hashing in day4) the selected peer fetch failing.","triggerScenarios":"GetterFunc returns an error on cache miss; remote peer HTTP call fails or times out; backend datastore unavailable during a miss.","commonSituations":"One node of the hash ring is down; DB outage; serialization/nil handling bug in the getter; wrong peer address registered in the pool.","solutions":["Read the 500 body for the underlying err.Error() message.","Verify peer addresses/health — remove or replace dead nodes in the consistent-hash ring.","Fix the GetterFunc to handle 'not found' and transient backend errors gracefully.","Add client-side retry for transient 500s."],"exampleFix":"// before: dead peer in ring\npeers := []string{\"http://10.0.0.1:8001\", \"http://10.0.0.2:8001\"} // .2 is down\n// after: health-check peers and only register live ones\npeers := filterHealthy([]string{\"http://10.0.0.1:8001\", \"http://10.0.0.2:8001\"})","handlingStrategy":"retry","validationCode":"// pre-flight peer health before reads\nfunc peerAlive(addr string) bool {\n    resp, err := http.Get(addr + \"/healthz\")\n    return err == nil && resp.StatusCode == http.StatusOK\n}","typeGuard":null,"tryCatchPattern":"// Go: retry transient 500s from the cache endpoint\nvar last error\nfor i := 0; i < 3; i++ {\n    resp, err := http.Get(url)\n    if err == nil && resp.StatusCode == http.StatusOK {\n        return io.ReadAll(resp.Body)\n    }\n    if resp != nil && resp.StatusCode == http.StatusInternalServerError {\n        last = fmt.Errorf(\"peer error (attempt %d)\", i+1)\n        time.Sleep(50 * time.Millisecond)\n        continue\n    }\n    break\n}\nreturn last","preventionTips":["Health-check peers and evict dead ones from the consistent-hash ring.","Harden GetterFuncs with timeouts/retries and clean not-found handling.","Log the server-side error so the 500 body is actionable.","Keep peer address lists generated from actual listen addresses, not hand-typed."],"tags":["http","cache","internal-server-error","getter","consistent-hash"],"backgroundTag":"cache-getter-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"}