{"record":{"id":"04ccf95cb0b721cb","repo":"Billionmail/BillionMail","slug":"key-cannot-be-empty","errorCode":null,"errorMessage":"key cannot be empty","messagePattern":"key cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/public/options_mgr.go","lineNumber":32,"sourceCode":"\tcache      *gcache.Cache // Cache instance\n\texpiration time.Duration // Cache expiration time\n}\n\n// 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","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/public/options_mgr.go#L14-L50","documentation":"OptionsMgr.SetOption in core/internal/service/public/options_mgr.go stores a key/value option, serializing the value as JSON. It rejects an empty key with \"key cannot be empty\" as a fail-fast guard. This is a caller validation error — the option is never written.","triggerScenarios":"Calling OptionsMgrInstance.SetOption(ctx, \"\", value) — usually the key came from an unvalidated request field, a missing map entry, or a variable that failed to initialize to a non-empty string.","commonSituations":"Settings UI posting an option whose name field was left blank, refactored code where a key constant was removed/renamed to empty, or dynamic keys built from DB rows containing empty strings.","solutions":["Ensure a non-empty key is supplied; check the constant/variable used for the key name.","Add upstream validation on the API/controller layer to reject empty option keys with a clear message.","Log the call site to find where the empty key originates (often a missing default or a map miss)."],"exampleFix":"// before\nkey := cfg.OptionName // \"\"\nOptionsMgrInstance.SetOption(ctx, key, val) // key cannot be empty\n// after\nif strings.TrimSpace(cfg.OptionName) == \"\" {\n    return gerror.New(\"option name is required\")\n}\nreturn OptionsMgrInstance.SetOption(ctx, cfg.OptionName, val)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(key) == \"\" {\n    return errors.New(\"option key is required\")\n}\nerr := OptionsMgrInstance.SetOption(ctx, key, value)","typeGuard":"func hasKey(key string) bool { return strings.TrimSpace(key) != \"\" }","tryCatchPattern":"if err := OptionsMgrInstance.SetOption(ctx, key, value); err != nil {\n    if err.Error() == \"key cannot be empty\" {\n        return fmt.Errorf(\"option name missing at %s — check the constant or request field\", caller)\n    }\n    return err\n}","preventionTips":["Define option keys as named constants, never inline strings","Validate option keys in controllers before reaching the manager","Log the call stack when an empty key is detected to find the source"],"tags":["validation","options","configuration","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"}