{"record":{"id":"8e61d989ed172407","repo":"Billionmail/BillionMail","slug":"failed-to-parse-alert-settings-v","errorCode":null,"errorMessage":"failed to parse alert settings: %v","messagePattern":"failed to parse alert settings: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/internal/service/domains/blacklist.go","lineNumber":468,"sourceCode":"\tRecipientList []string `json:\"recipient_list\"`\n}\n\nfunc loadBlacklistAlertSettingsForAlert() (*BlacklistAlertSettings, error) {\n\talertSettingsFile := public.AbsPath(\"../core/data/blacklist_alert_settings.json\")\n\n\tif !gfile.Exists(alertSettingsFile) {\n\t\treturn nil, fmt.Errorf(\"alert settings file not found\")\n\t}\n\n\tcontent := gfile.GetContents(alertSettingsFile)\n\tif content == \"\" {\n\t\treturn nil, fmt.Errorf(\"alert settings file is empty\")\n\t}\n\n\tvar settings BlacklistAlertSettings\n\terr := json.Unmarshal([]byte(content), &settings)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse alert settings: %v\", err)\n\t}\n\n\treturn &settings, nil\n}\n\nfunc sendAlertEmail(ctx context.Context, settings *BlacklistAlertSettings, subject, body string) error {\n\n\tsender := mail_service.NewEmailSender()\n\tsender.Host = settings.SMTPServer\n\tsender.Port = fmt.Sprintf(\"%d\", settings.SMTPPort)\n\tsender.Email = settings.SenderEmail\n\tsender.UserName = settings.SenderEmail\n\tsender.Password = settings.SMTPPassword\n\n\terr := sender.Connect()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to connect to SMTP server: %v\", err)\n\t}","sourceCodeStart":450,"sourceCodeEnd":486,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/domains/blacklist.go#L450-L486","documentation":"loadBlacklistAlertSettingsForAlert unmarshals the file contents into the BlacklistAlertSettings struct; any json.Unmarshal error (malformed JSON, wrong types, invalid syntax) is wrapped as 'failed to parse alert settings: %v'. The %v carries the encoding/json detail such as the byte offset and expected type.","triggerScenarios":"sendBlacklistAlert runs while blacklist_alert_settings.json contains syntactically invalid JSON or fields whose types don't match the struct (e.g. a string where RecipientList expects an array, trailing commas, single quotes, BOM, or comments).","commonSituations":"Hand-edited settings file with a syntax mistake; concurrent writes producing interleaved/partial JSON; older schema file no longer matching the struct after an upgrade; file corrupted by a crash mid-write.","solutions":["Validate the JSON: jq . ../core/data/blacklist_alert_settings.json and fix the reported offset error","Re-save settings via the admin UI to regenerate a schema-correct file","Compare the file against the BlacklistAlertSettings struct fields/types in the current code version","Write settings atomically (temp file + rename) to prevent partial JSON on crash"],"exampleFix":"// before\nerr := json.Unmarshal([]byte(content), &settings)\nif err != nil {\n\treturn nil, fmt.Errorf(\"failed to parse alert settings: %v\", err)\n}\n// after\nerr := json.Unmarshal([]byte(content), &settings)\nif err != nil {\n\treturn nil, fmt.Errorf(\"failed to parse alert settings from %s: %w\", alertSettingsFile, err)\n}","handlingStrategy":"validation","validationCode":"content := gfile.GetContents(settingsPath)\nvar probe map[string]any\nif err := json.Unmarshal([]byte(content), &probe); err != nil {\n\treturn fmt.Errorf(\"alert settings JSON invalid: %w\", err)\n}","typeGuard":"func validBlacklistAlertSettings(b []byte) bool {\n\tvar s BlacklistAlertSettings\n\treturn json.Unmarshal(b, &s) == nil\n}","tryCatchPattern":"settings, err := loadBlacklistAlertSettingsForAlert()\nvar perr *json.SyntaxError\nif err != nil && errors.As(err, perr) {\n\t// report perr.Offset so the admin can fix the exact spot in the JSON\n}","preventionTips":["Run jq/python -m json.tool on hand-edited settings files before deploying","Avoid manual edits with trailing commas, comments, or wrong value types","Keep settings schema changes backward compatible across upgrades","Serialize settings with a single atomic writer to prevent partial JSON"],"tags":["json","configuration","parsing"],"backgroundTag":"json-parse-error","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}