{"record":{"id":"075367e88ec0cbdc","repo":"vitessio/vitess","slug":"nil-not-allowed","errorCode":null,"errorMessage":"nil not allowed","messagePattern":"nil not allowed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/stats/export.go","lineNumber":87,"sourceCode":"const StatsAllStr = \"all\"\n\n// NewVarHook is the type of a hook to export variables in a different way\ntype NewVarHook func(name string, v expvar.Var)\n\ntype varGroup struct {\n\tsync.Mutex\n\tvars       map[string]expvar.Var\n\tnewVarHook NewVarHook\n}\n\nfunc (vg *varGroup) register(nvh NewVarHook) {\n\tvg.Lock()\n\tdefer vg.Unlock()\n\tif vg.newVarHook != nil {\n\t\tpanic(\"You've already registered a function\")\n\t}\n\tif nvh == nil {\n\t\tpanic(\"nil not allowed\")\n\t}\n\tvg.newVarHook = nvh\n\t// Call hook on existing vars because some might have been\n\t// created before the call to register\n\tfor k, v := range vg.vars {\n\t\tnvh(k, v)\n\t}\n\tvg.vars = nil\n}\n\nfunc (vg *varGroup) publish(name string, v expvar.Var) {\n\tif isVarDropped(name) {\n\t\treturn\n\t}\n\tvg.Lock()\n\tdefer vg.Unlock()\n\n\texpvar.Publish(name, v)","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/stats/export.go#L69-L105","documentation":"stats.register installs a global variable hook (newVarHook) on a varGroup, and only one hook may ever exist per group. The library panics if the caller passes a nil hook function, since a nil hook would silently disable stats export and break the invariant that every registered var is delivered to the hook.","triggerScenarios":"Calling stats.register(nil) (or the package-level StatsCmdHook/Exporter registration wrappers with a nil function) before any hook has been set.","commonSituations":"A variable holding the hook function was not yet assigned when registration runs (initialization-order bug); a refactor removed the callback body leaving a nil func; wiring code conditionally skips assigning the hook in some build modes.","solutions":["Pass a non-nil function to stats.register, even a no-op like func(string, interface{}) {} if you do not need the values yet.","Check the code path that builds the hook function and ensure it is assigned before register is called.","Add an assert/unit test that the hook is non-nil before calling register to fail at the right place."],"exampleFix":"// before\nvar hook func(string, interface{})\nstats.register(hook) // panics: nil not allowed\n// after\nvar hook func(string, interface{}) = func(_ string, _ interface{}) {}\nstats.register(hook)","handlingStrategy":"validation","validationCode":"if hook == nil {\n    hook = func(string, interface{}) {} // or return an error before calling register\n}\nstats.register(hook)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never pass function variables that may be nil into registration APIs; initialize hooks at declaration.","Add a unit test exercising the registration path on startup.","Keep hook assignment and register call adjacent in the same init function."],"tags":["go","stats","panic","nil-argument"],"backgroundTag":"nil-callback-argument","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}