{"record":{"id":"2204f843021507d0","repo":"Billionmail/BillionMail","slug":"value-cannot-be-nil","errorCode":null,"errorMessage":"value cannot be nil","messagePattern":"value cannot be nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/public/options_mgr.go","lineNumber":36,"sourceCode":"// NewOptionsMgr Create options manager\nfunc NewOptionsMgr() *OptionsMgr {\n\treturn &OptionsMgr{\n\t\tcache:      gcache.New(),\n\t\texpiration: time.Hour * 24, // Default 24 hours cache\n\t}\n}\n\n// OptionsMgrInstance Options manager singleton\nvar OptionsMgrInstance = NewOptionsMgr()\n\n// SetOption Set option\nfunc (o *OptionsMgr) SetOption(ctx context.Context, key string, value interface{}) error {\n\tif key == \"\" {\n\t\treturn errors.New(\"key cannot be empty\")\n\t}\n\n\tif value == nil {\n\t\treturn errors.New(\"value cannot be nil\")\n\t}\n\n\t// Serialize value\n\tjsonValue, err := o.serialize(value)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Save to database\n\tif err := o.saveToDatabase(ctx, key, jsonValue); err != nil {\n\t\treturn err\n\t}\n\n\t// Update cache\n\tcacheKey := o.buildCacheKey(key)\n\tif err := o.cache.Set(ctx, cacheKey, jsonValue, o.expiration); err != nil {\n\t\treturn err\n\t}","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/public/options_mgr.go#L18-L54","documentation":"OptionsMgr.SetOption in core/internal/service/public/options_mgr.go rejects a nil value with \"value cannot be nil\" before serializing, because it JSON-serializes the value and a nil interface{} cannot be meaningfully stored. This fail-fast guard prevents writing unusable option records.","triggerScenarios":"Calling OptionsMgrInstance.SetOption(ctx, key, nil) — commonly passing a nil interface from an uninitialized pointer, a map lookup that returned the zero value with ok=false ignored, or an optional request field that was never set.","commonSituations":"Settings handlers binding request JSON where the value field is absent, refactors where the value variable lost its default, or code passing the result of a failed type assertion (var v T; v == nil).","solutions":["Provide a concrete value or a typed zero value (e.g. \"\", 0, false) instead of nil.","Check where the value comes from — handle missing map entries and unset request fields explicitly before calling.","If deleting an option is intended, use the manager's delete/removal method instead of setting nil."],"exampleFix":"// before\nvar val interface{} // nil\nOptionsMgrInstance.SetOption(ctx, \"site_name\", val) // value cannot be nil\n// after\nval := req.SiteName\nif val == nil {\n    val = \"\" // store explicit empty value or skip the update\n}\nreturn OptionsMgrInstance.SetOption(ctx, \"site_name\", val)","handlingStrategy":"validation","validationCode":"if value == nil {\n    return errors.New(\"option value is required; use a typed zero value or delete the option instead\")\n}\nerr := OptionsMgrInstance.SetOption(ctx, key, value)","typeGuard":"func hasValue(v interface{}) bool { return v != nil }","tryCatchPattern":"if err := OptionsMgrInstance.SetOption(ctx, key, value); err != nil {\n    if err.Error() == \"value cannot be nil\" {\n        return fmt.Errorf(\"option %q has no value; pass a concrete value or remove the option\", key)\n    }\n    return err\n}","preventionTips":["Use typed zero values (\"\", 0, false) rather than nil for defaults","Check the ok flag on map lookups and type assertions before using the result","Use a dedicated delete method for removing options instead of setting nil","Bind request structs with concrete types so missing fields become zero values, not nil"],"tags":["validation","options","nil-value","go"],"backgroundTag":"empty-required-field","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}