Billionmail/BillionMail · warning
alert settings file is empty
Error message
alert settings file is empty
What it means
After confirming blacklist_alert_settings.json exists, loadBlacklistAlertSettingsForAlert reads it with gfile.GetContents and returns 'alert settings file is empty' when the content is an empty string. This protects json.Unmarshal from a confusing 'unexpected end of JSON input' error by reporting the actual problem.
Source
Thrown at core/internal/service/domains/blacklist.go:462
type BlacklistAlertSettings struct {
Name string `json:"name"`
SenderEmail string `json:"sender_email"`
SMTPPassword string `json:"smtp_password"`
SMTPServer string `json:"smtp_server"`
SMTPPort int `json:"smtp_port"`
RecipientList []string `json:"recipient_list"`
}
func loadBlacklistAlertSettingsForAlert() (*BlacklistAlertSettings, error) {
alertSettingsFile := public.AbsPath("../core/data/blacklist_alert_settings.json")
if !gfile.Exists(alertSettingsFile) {
return nil, fmt.Errorf("alert settings file not found")
}
content := gfile.GetContents(alertSettingsFile)
if content == "" {
return nil, fmt.Errorf("alert settings file is empty")
}
var settings BlacklistAlertSettings
err := json.Unmarshal([]byte(content), &settings)
if err != nil {
return nil, fmt.Errorf("failed to parse alert settings: %v", err)
}
return &settings, nil
}
func sendAlertEmail(ctx context.Context, settings *BlacklistAlertSettings, subject, body string) error {
sender := mail_service.NewEmailSender()
sender.Host = settings.SMTPServer
sender.Port = fmt.Sprintf("%d", settings.SMTPPort)
sender.Email = settings.SenderEmail
sender.UserName = settings.SenderEmailView on GitHub (pinned to fc36c76c05)
Solutions
- Re-save the blacklist alert settings through the admin UI to rewrite the file with valid JSON
- Validate the file content: cat ../core/data/blacklist_alert_settings.json and restore a backup if empty
- Ensure settings writes are atomic (write temp file + rename) to avoid truncation
- Check disk space and volume mount health on the host
Example fix
// before
content := gfile.GetContents(alertSettingsFile)
if content == "" {
return nil, fmt.Errorf("alert settings file is empty")
}
// after
content := strings.TrimSpace(gfile.GetContents(alertSettingsFile))
if content == "" {
return nil, fmt.Errorf("alert settings file %s is empty; re-save alert settings in the admin UI", alertSettingsFile)
} Defensive patterns
Strategy: validation
Validate before calling
content := gfile.GetContents(public.AbsPath("../core/data/blacklist_alert_settings.json"))
if strings.TrimSpace(content) == "" {
return fmt.Errorf("alert settings file is empty; re-save settings in the admin UI")
}
if !json.Valid([]byte(content)) {
return fmt.Errorf("alert settings file is not valid JSON")
} Try / catch
settings, err := loadBlacklistAlertSettingsForAlert()
if err != nil && strings.Contains(err.Error(), "alert settings file is empty") {
// regenerate defaults or notify admin to re-save settings
} Prevention
- Always save settings through the UI/API rather than hand-editing the file
- Use atomic writes (temp file + rename) when persisting settings
- Monitor the settings file size/content after upgrades or restores
- Restore from backup if the file is found empty on boot
When it happens
Trigger: sendBlacklistAlert runs while ../core/data/blacklist_alert_settings.json exists but contains zero bytes — e.g. a truncated write, an editor/UI that created the file without content, or a volume mount failure yielding an empty placeholder file.
Common situations: Settings saved to the file failed mid-write (disk full, container killed); a user created the file manually but left it empty; an empty bind-mounted file shadows the real one; crash during initial settings serialization.
Related errors
- error marshalling knowledge base: %v
- error reading knowledge base: %v
- error reading images configuration: %v
- alert settings file not found
- failed to parse alert settings: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/37af508609e0b7f4.
Report an issue: GitHub.