{"record":{"id":"a6758ea2aba40004","repo":"geektutu/7days-golang","slug":"nil-getter-a6758e","errorCode":null,"errorMessage":"nil Getter","messagePattern":"nil Getter","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-cache/day6-single-flight/geecache/geecache.go","lineNumber":42,"sourceCode":"}\n\n// A GetterFunc implements Getter with a function.\ntype GetterFunc func(key string) ([]byte, error)\n\n// Get implements Getter interface function\nfunc (f GetterFunc) Get(key string) ([]byte, error) {\n\treturn f(key)\n}\n\nvar (\n\tmu     sync.RWMutex\n\tgroups = make(map[string]*Group)\n)\n\n// NewGroup create a new instance of Group\nfunc NewGroup(name string, cacheBytes int64, getter Getter) *Group {\n\tif getter == nil {\n\t\tpanic(\"nil Getter\")\n\t}\n\tmu.Lock()\n\tdefer mu.Unlock()\n\tg := &Group{\n\t\tname:      name,\n\t\tgetter:    getter,\n\t\tmainCache: cache{cacheBytes: cacheBytes},\n\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]","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-cache/day6-single-flight/geecache/geecache.go#L24-L60","documentation":"Same \"nil Getter\" panic as errors 90/92/94, in the day6-single-flight version: NewGroup rejects a nil getter because the Group needs a loader to resolve cache misses. The panic fails fast at construction time.","triggerScenarios":"Passing nil (or a typed-nil interface) as the third argument to geecache.NewGroup.","commonSituations":"Getter wired to a service not yet initialized; refactoring removed the assignment; test scaffolding passing nil to satisfy the signature.","solutions":["Provide a real Getter via geecache.GetterFunc or a struct implementing Getter","Fix initialization ordering so the data source exists before group creation","Add a constructor wrapper that validates the getter in your own code"],"exampleFix":"// before\ngeecache.NewGroup(\"scores\", 2<<20, nil) // panic\n// after\ngeecache.NewGroup(\"scores\", 2<<20, geecache.GetterFunc(func(key string) ([]byte, error) {\n    return slowDBLookup(key)\n}))","handlingStrategy":"validation","validationCode":"if getter == nil {\n    panic(\"NewGroup requires a non-nil Getter\")\n}\ng := geecache.NewGroup(\"scores\", 2<<20, getter)","typeGuard":"func hasLoader(g geecache.Getter) bool { return g != nil }","tryCatchPattern":"// Handle at process startup, not per call:\ndefer func() {\n    if r := recover(); r != nil { log.Fatalf(\"group creation panicked: %v\", r) }\n}()","preventionTips":["Use geecache.GetterFunc so function values are always wrapped non-nil","Initialize backing stores before group construction","Add a nil-getter check in your own config-to-group wiring"],"tags":["go","cache","panic","nil-pointer"],"backgroundTag":"nil-cache-getter","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"}