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.SenderEmail

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Re-save the blacklist alert settings through the admin UI to rewrite the file with valid JSON
  2. Validate the file content: cat ../core/data/blacklist_alert_settings.json and restore a backup if empty
  3. Ensure settings writes are atomic (write temp file + rename) to avoid truncation
  4. 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

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


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/37af508609e0b7f4. Report an issue: GitHub.