{"record":{"id":"7f921e1849ec8ba9","repo":"geektutu/7days-golang","slug":"err-error-7f921e","errorCode":null,"errorMessage":"err.Error()","messagePattern":"err\\.Error\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"gee-cache/day5-multi-nodes/geecache/http.go","lineNumber":66,"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\n// Set updates the pool's list of peers.\nfunc (p *HTTPPool) Set(peers ...string) {\n\tp.mu.Lock()\n\tdefer p.mu.Unlock()\n\tp.peers = consistenthash.New(defaultReplicas, nil)\n\tp.peers.Add(peers...)\n\tp.httpGetters = make(map[string]*httpGetter, len(peers))\n\tfor _, peer := range peers {\n\t\tp.httpGetters[peer] = &httpGetter{baseURL: peer + p.basePath}\n\t}\n}","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day5-multi-nodes/geecache/http.go#L48-L84","documentation":"day5 ServeHTTP: group found, but group.Get(key) errored and the message is forwarded as HTTP 500. In the multi-node setup the usual sources are a failing GetterFunc or a failed remote fetch from a peer node selected via consistent hashing / Peek.","triggerScenarios":"GetterFunc returns an error on miss; peer-to-peer HTTP fetch (proto exchange) fails; backend datastore error during load; dead or misconfigured peer base URLs.","commonSituations":"A cache peer crashed or was redeployed; wrong peer address in the pool; DB outage; network partition between nodes.","solutions":["Inspect the 500 body for the underlying err.Error() text.","Check peer health and peer base-URL registration; remove dead peers from the ring.","Harden the GetterFunc (timeouts, retries, clean 'not found' handling).","Retry the request client-side if a peer was momentarily unavailable."],"exampleFix":"// before: peer URL typo\np.SetPeers(peers...)\n// peers contains \"http://127.0.0.1:7002\" but node listens on 8002\n// after: generate peer URLs from the actual listen addresses\naddrs := []string{\":8001\", \":8002\", \":8003\"}\nvar peers []string\nfor _, a := range addrs {\n    peers = append(peers, \"http://127.0.0.1\"+a)\n}","handlingStrategy":"retry","validationCode":"// day5: verify peer connectivity before reads\nfunc checkPeer(addr string) error {\n    conn, err := net.DialTimeout(\"tcp\", strings.TrimPrefix(addr, \"http://\"), time.Second)\n    if err != nil { return err }\n    return conn.Close()\n}","typeGuard":null,"tryCatchPattern":"// Go: read the 500 body (server's err.Error()) and retry once\nresp, err := http.Get(url)\nif err != nil { return err }\nif resp.StatusCode == http.StatusInternalServerError {\n    body, _ := io.ReadAll(resp.Body)\n    time.Sleep(100 * time.Millisecond)\n    return fmt.Errorf(\"cache get failed: %s (will retry)\", body)\n}","preventionTips":["Keep peer URLs generated from real listen addresses and health-check them.","Give GetterFuncs timeouts/retries; return distinguishable not-found vs error states.","Log server-side errors so forwarded 500 bodies stay meaningful.","Retry transient failures client-side; monitor 500 rates per peer."],"tags":["http","cache","internal-server-error","getter","multi-node"],"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"}