Billionmail/BillionMail · error
Failed to write DKIM sign config: %v
Error message
Failed to write DKIM sign config: %v
What it means
Thrown when public.WriteFile fails to persist the modified rspamd DKIM signing config after inserting the domain's DKIM block before #BT_DOMAIN_DKIM_END. The library aborts the signing-config update (and skips the rspamd restart) because leaving the file unwritten would desync signing configuration.
Source
Thrown at core/internal/service/domains/domains.go:628
if public.FileExists(signConfPath) {
signContent, err = public.ReadFile(signConfPath)
if err != nil {
err = fmt.Errorf("Failed to read DKIM sign config: %v", err)
return
}
}
// Remove old config block if it exists
pattern := fmt.Sprintf(`(?s)#%s_DKIM_BEGIN.*?#%s_DKIM_END\s*`, domain, domain)
signContent, err = gregex.ReplaceString(pattern, "", signContent)
if err != nil {
return
}
signContent = strings.Replace(signContent, "#BT_DOMAIN_DKIM_END", signConf+"\n#BT_DOMAIN_DKIM_END", 1)
_, err = public.WriteFile(signConfPath, signContent)
if err != nil {
err = fmt.Errorf("Failed to write DKIM sign config: %v", err)
return
}
// Restart rspamd service
err = dk.RestartContainerByName(context.Background(), consts.SERVICES.Rspamd)
if err != nil {
err = fmt.Errorf("Failed to restart rspamd container: %v", err)
return
}
}
}
// DKIM public key is typically stored in a specific location in the container or host
// Assuming we use docker exec to read the DKIM public key from the rspamd container
dkimPub, err := public.ReadFile(dkimPubPath)
if err != nil {
err = fmt.Errorf("Cannot read DKIM public key: %v", err)
returnView on GitHub (pinned to fc36c76c05)
Solutions
- Free disk space (df -h) if ENOSPC, then re-run RepairDKIMSigningConfig
- Fix ownership/permissions on the config file and its directory so the writer can create/truncate it
- Check for immutable flag (lsattr/chattr -i) and read-only mounts
- Verify the path's parent directory exists and is writable
Example fix
// before
_, err = public.WriteFile(signConfPath, signContent)
// after: diagnose write failure explicitly
if errors.Is(err, syscall.ENOSPC) {
log.Printf("disk full; free space before retrying DKIM config write")
}
_, err = public.WriteFile(signConfPath, signContent) Defensive patterns
Strategy: try-catch
Validate before calling
fi, err := os.Stat(filepath.Dir(signConfPath)); if err != nil || !fi.IsDir() { return fmt.Errorf("config dir missing") }
if err := syscall.Access(filepath.Dir(signConfPath), os.O_RDWR); err != nil { return fmt.Errorf("config dir not writable") } Type guard
func isWritable(path string) bool {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil { return false }
f.Close()
return true
} Try / catch
if _, err := public.WriteFile(signConfPath, signContent); err != nil {
log.Printf("DKIM sign config write failed at %s: %v — check disk space, perms, read-only mounts", signConfPath, err)
return err
} Prevention
- Monitor disk usage on the config volume and alert before it fills
- Never mount the rspamd config volume read-only when DKIM repair is enabled
- Avoid chattr +i or hardening scripts that lock mail config files
When it happens
Trigger: public.WriteFile(signConfPath, signContent) returns an error — read-only filesystem, disk full (ENOSPC), permission denied on write/open for truncate, parent directory missing, or immutable file attribute.
Common situations: Disk full on the mail server volume, config volume mounted read-only after a container update, rspamd config owned by _rspamd while BillionMail writes as another user, chattr +i set by hardening scripts.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- failed to write DKIM signing config: %v
- Failed to write DKIM public key: %v
- Failed to read DKIM sign config: %v
- Cannot read DKIM public key: %v
- Failed to generate DKIM key pair: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/bd5160e76d8c6964.
Report an issue: GitHub.