{"record":{"id":"90557e97d08f0d8f","repo":"geektutu/7days-golang","slug":"key-is-required-90557e","errorCode":null,"errorMessage":"key is required","messagePattern":"key is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-cache/day7-proto-buf/geecache/geecache.go","lineNumber":69,"sourceCode":"\t\tloader:    &singleflight.Group{},\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":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day7-proto-buf/geecache/geecache.go#L51-L87","documentation":"Same empty-key guard in the day7-proto-buf build: Group.Get rejects an empty key up front. In day7 the peer protocol uses protobuf responses, but validation still happens before the local lookup, peer fetch, or loader invocation.","triggerScenarios":"group.Get(\"\"); empty key segment parsed from the /_geecache/<group>/<key> URL path in the day7 server; unvalidated handler parameters.","commonSituations":"Client requests with a trailing slash and no key; keys sourced from empty request fields or config; tests hitting Get with empty strings.","solutions":["Validate the key (non-empty after trim) before calling group.Get","Fix the upstream key construction (path parsing, request params)","Reject empty-key requests with 400 at the HTTP boundary"],"exampleFix":"// before\nkey := r.URL.Path[len(basePath)+len(groupName)+1:]\nv, err := g.Get(key)\n// after\nif key == \"\" {\n    http.Error(w, \"key is required\", http.StatusBadRequest)\n    return\n}\nv, err := g.Get(key)","handlingStrategy":"validation","validationCode":"if k := strings.TrimSpace(key); k == \"\" {\n    http.Error(w, \"key is required\", http.StatusBadRequest)\n    return\n}\nv, err := group.Get(strings.TrimSpace(key))","typeGuard":"func hasKey(r *http.Request) bool {\n    _, key := splitGroupKey(r.URL.Path)\n    return strings.TrimSpace(key) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Validate the key path segment at the top of the peer HTTP handler","Never pass raw request input into Get without trimming","Cover empty-key requests in handler tests"],"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"}