{"record":{"id":"f9775b761d2262f5","repo":"geektutu/7days-golang","slug":"key-is-required-f9775b","errorCode":null,"errorMessage":"key is required","messagePattern":"key is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-cache/day5-multi-nodes/geecache/geecache.go","lineNumber":63,"sourceCode":"\t\tmainCache: cache{cacheBytes: cacheBytes},\n\t}\n\tgroups[name] = g\n\treturn g\n}\n\n// GetGroup returns the named group previously created with NewGroup, or\n// nil if there's no such group.\nfunc GetGroup(name string) *Group {\n\tmu.RLock()\n\tg := groups[name]\n\tmu.RUnlock()\n\treturn g\n}\n\n// Get value for a key from cache\nfunc (g *Group) Get(key string) (ByteView, error) {\n\tif key == \"\" {\n\t\treturn ByteView{}, fmt.Errorf(\"key is required\")\n\t}\n\n\tif v, ok := g.mainCache.get(key); ok {\n\t\tlog.Println(\"[GeeCache] hit\")\n\t\treturn v, nil\n\t}\n\n\treturn g.load(key)\n}\n\n// RegisterPeers registers a PeerPicker for choosing remote peer\nfunc (g *Group) RegisterPeers(peers PeerPicker) {\n\tif g.peers != nil {\n\t\tpanic(\"RegisterPeerPicker called more than once\")\n\t}\n\tg.peers = peers\n}\n","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day5-multi-nodes/geecache/geecache.go#L45-L81","documentation":"Group.Get validates that the cache key is a non-empty string before doing any lookup. GeeCache keys are the identity of a cache entry, and an empty key can never exist in mainCache, so the library fails fast with a clear message instead of a silent cache miss that would then trigger a peer fetch or loader callback for a bogus key. This guard runs before the local cache lookup, the peer selection, and the user-supplied Getter.","triggerScenarios":"Calling group.Get(\"\") with an empty string key; building a key from string concatenation/formatting where a variable part is empty (e.g. fmt.Sprintf(\"user:%d\", 0 misused) or a missing query parameter); calling Get before the key variable is initialized.","commonSituations":"HTTP handlers that pass a request parameter straight through without trimming/validating it; keys derived from config or environment values that are unset; refactored code where a prefix/suffix component of a composite key became empty.","solutions":["Check the key for emptiness (after strings.TrimSpace) at the call site before invoking group.Get and return a client-facing bad-request error","Trace where the key is constructed (handler params, path segments, config) and fix the upstream source of the empty value","If empty keys are legitimate, define a sentinel/mapped key instead of using \"\""],"exampleFix":"// before\nv, err := group.Get(key) // key may be \"\"\n// after\nif key = strings.TrimSpace(key); key == \"\" {\n    http.Error(w, \"missing cache key\", http.StatusBadRequest)\n    return\n}\nv, err := group.Get(key)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(key) == \"\" {\n    return ByteView{}, errors.New(\"cache key must be non-empty\")\n}\nv, err := group.Get(key)","typeGuard":"func validKey(k string) bool { return strings.TrimSpace(k) != \"\" }","tryCatchPattern":null,"preventionTips":["Always trim and validate keys at the HTTP handler boundary before reaching the cache","Build composite keys with a helper that asserts every component is non-empty","Add a unit test asserting Get(\"\") fails fast rather than reaching the loader"],"tags":["cache","input-validation","go"],"backgroundTag":"empty-cache-key","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"}