Billionmail/BillionMail · error
Failed to change DKIM private key permissions: %v
Error message
Failed to change DKIM private key permissions: %v
What it means
After generating keys, getDKIMRecordWithKeySize runs os.Chmod(dkimPriPath, 0644) so Rspamd can read the private key. This error wraps a chmod failure. Without readable permissions, DKIM signing will fail later even though the keys exist.
Source
Thrown at core/internal/service/domains/domains.go:571
var res *v2.ExecResult
res, err = dk.ExecCommandByName(context.Background(), consts.SERVICES.Rspamd, []string{"rspamadm", "dkim_keygen", "-s", selector, "-b", fmt.Sprintf("%d", keySize), "-d", domain, "-k", fmt.Sprintf("/var/lib/rspamd/dkim/%s/%s.private", domain, selector)}, "root")
if err != nil {
err = fmt.Errorf("Failed to generate DKIM key pair: %v", err)
return
}
if res != nil {
_, err = public.WriteFile(dkimPubPath, res.Output)
if err != nil {
err = fmt.Errorf("Failed to write DKIM public key: %v", err)
return
}
}
// update dkim private key file permission to 0644
err = os.Chmod(dkimPriPath, 0644)
if err != nil {
err = fmt.Errorf("Failed to change DKIM private key permissions: %v", err)
return
}
// Skip DKIM signing config for relay-mapped domains — relay provider signs
relayDomains, relayErr := GetRelayDomains(context.Background())
if relayErr != nil {
g.Log().Warning(context.Background(), "Failed to check relay domains for DKIM signing:", relayErr)
relayDomains = make(map[string]bool)
}
if !relayDomains[domain] {
// build DKIM Sign config
signConf := fmt.Sprintf(`
#%s_DKIM_BEGIN
%s {
selectors [
{
path: "/var/lib/rspamd/dkim/%s/default.private";View on GitHub (pinned to fc36c76c05)
Solutions
- Check the wrapped error for EPERM/EACCES and run the process with rights over the dkim directory, or chown the files to the service user
- Confirm dkimPriPath exists (a prior generation failure would surface here) and points at the rspamd volume mount
- Verify the rspamd container user can read 0644 files on that volume
- Retry GetDKIMRecord after fixing mount/permission issues
Example fix
// before
err = os.Chmod(dkimPriPath, 0644)
if err != nil { err = fmt.Errorf("Failed to change DKIM private key permissions: %v", err); return }
// after
if _, statErr := os.Stat(dkimPriPath); statErr != nil {
err = fmt.Errorf("DKIM private key missing before chmod: %v", statErr)
return
}
if err = os.Chmod(dkimPriPath, 0644); err != nil {
err = fmt.Errorf("Failed to chmod DKIM private key %s (check volume ownership): %v", dkimPriPath, err)
return
} Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(dkimPriPath)
if err != nil { return fmt.Errorf("private key missing: %v", err) }
if info.Mode().Perm() == 0644 { return nil } // already correct Try / catch
if err := os.Chmod(dkimPriPath, 0644); err != nil {
if errors.Is(err, os.ErrPermission) {
logger.Warnf(ctx, "cannot chmod %s (not owner); signing may fail", dkimPriPath)
}
return fmt.Errorf("Failed to change DKIM private key permissions: %v", err)
} Prevention
- Run the management process with the same uid/gid that owns the DKIM volume
- Set umask/creation mode correctly at key write time so chmod is a no-op safety net
- Audit volume mount options (no read-only, no noexec interference)
- Verify rspamd can read the key after generation with a test exec (cat the .private file)
When it happens
Trigger: getDKIMRecordWithKeySize when os.Chmod on the freshly generated private key fails — file owned by another uid (rspamd container user vs host process), read-only mount, or the private path doesn't exist because generation silently failed earlier.
Common situations: Host process runs as non-root while key files are root-owned; DKIM volume mounted with restrictive options; AppArmor/SELinux denials; race where keygen wrote to a container-internal path not mapped to dkimPriPath.
Related errors
- failed to change DKIM file permissions: %v
- Failed to read DKIM sign config: %v
- failed to send confirmation email: %w
- failed to save private key: %v
- error reading project configuration file: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/84fcf7aebe866e8e.
Report an issue: GitHub.