Billionmail/BillionMail · error
failed to write certificate file: %v
Error message
failed to write certificate file: %v
What it means
updatePostfixConfig in the BillionMail mail_service Certificate module wraps the failure of os.WriteFile when saving the TLS public certificate to <SSL_PATH>/postfix.crt. The underlying OS error (permissions, missing directory, read-only mount, disk full) is embedded in the message. It is thrown while applying a newly issued/updated certificate so Postfix can serve TLS.
Source
Thrown at core/internal/service/mail_service/certificate.go:240
}
return nil
}
// updatePostfixConfig updates Postfix configuration with new certificate
func (c *Certificate) updatePostfixConfig(csrPem, keyPem string) error {
mainCf := public.AbsPath(consts.POSTFIX_MAIN_CONF)
content, err := os.ReadFile(mainCf)
if err != nil {
return fmt.Errorf("failed to read postfix config: %v", err)
}
// Write certificate and key to files
certPath := public.AbsPath(filepath.Join(consts.SSL_PATH, "postfix.crt"))
keyPath := public.AbsPath(filepath.Join(consts.SSL_PATH, "postfix.key"))
if err := os.WriteFile(certPath, []byte(csrPem), 0755); err != nil {
return fmt.Errorf("failed to write certificate file: %v", err)
}
if err := os.WriteFile(keyPath, []byte(keyPem), 0755); err != nil {
return fmt.Errorf("failed to write key file: %v", err)
}
// Update SSL certificate configuration
config := string(content)
config = c.updateConfigLine(config, "smtpd_tls_key_file", keyPath)
config = c.updateConfigLine(config, "smtpd_tls_cert_file", certPath)
if err := os.WriteFile(mainCf, []byte(config), 0755); err != nil {
return fmt.Errorf("failed to write postfix config: %v", err)
}
return nil
}
View on GitHub (pinned to fc36c76c05)
Solutions
- Ensure the SSL_PATH directory exists and is writable (mkdir -p and chown the path for the process user, or fix the Docker volume mount).
- Check disk space (df -h) and inode usage on the SSL volume.
- Inspect the wrapped %v error in logs to identify the exact errno (EACCES vs ENOSPC vs EROFS).
- Run the container/service with sufficient privileges (root) since Postfix config paths are system locations.
- Retry SetSSL after fixing storage; verify postfix.crt was written.
Example fix
// before
if err := os.WriteFile(certPath, []byte(csrPem), 0755); err != nil {
return fmt.Errorf("failed to write certificate file: %v", err)
}
// after
if err := os.MkdirAll(filepath.Dir(certPath), 0755); err != nil {
return fmt.Errorf("failed to create ssl directory: %v", err)
}
if err := os.WriteFile(certPath, []byte(csrPem), 0644); err != nil {
return fmt.Errorf("failed to write certificate file %s: %w", certPath, err)
} Defensive patterns
Strategy: validation
Validate before calling
certPath := public.AbsPath(filepath.Join(consts.SSL_PATH, "postfix.crt"))
if err := os.MkdirAll(filepath.Dir(certPath), 0755); err != nil {
return err
}
if fi, err := os.Stat(filepath.Dir(certPath)); err != nil || !fi.IsDir() {
return fmt.Errorf("ssl dir not usable: %v", err)
}
if err := syscall.Access(filepath.Dir(certPath), unix.W_OK); err != nil {
return fmt.Errorf("ssl dir not writable: %v", err)
} Try / catch
cert, err := svc.SetSSL(ctx, domain, certPem, keyPem)
if err != nil && strings.Contains(err.Error(), "failed to write certificate file") {
log.Printf("check SSL volume mount/permissions/disk space: %v", err)
} Prevention
- Mount the SSL path as a dedicated writable Docker volume and never ':ro'.
- Run the app container with a user that owns the SSL directory.
- Pre-create SSL_PATH at container startup in the entrypoint script.
- Monitor disk space on the mail host (alert at 85%).
- Keep cert/key files at 0644/0600, not 0755.
When it happens
Trigger: Calling SetSSL or SetPostfixSSL when consts.SSL_PATH does not exist, the process lacks write permission to it, or the filesystem is full/read-only.
Common situations: Docker volume for the SSL path not mounted or mounted read-only; running container as non-root; SSL_PATH directory deleted by cleanup scripts; disk quota exhausted after bulk cert issuance.
Understand the failure class
Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to write key file: %v
- failed to write postfix config: %v
- Failed to save certificate file: {}
- Failed to save private key file: {}
- failed to save certificate: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/83aa5f345a818e20.
Report an issue: GitHub.