Billionmail/BillionMail · error
failed to save certificate: %v
Error message
failed to save certificate: %v
What it means
Apply throws this when public.WriteFile fails to save certificate.pem into cli.OutputPath after successful issuance, wrapping the OS error with %v. Like errors 111-112 but in the AcmeCLI.Apply path (file name derived from first domain under OutputPath).
Source
Thrown at core/internal/service/acme/cli.go:204
// Get certificate info
certInfo := GetCertInfo(certificate)
fmt.Printf("Certificate issued successfully:\n")
fmt.Printf(" Subject: %s\n", certInfo.Subject)
fmt.Printf(" Issuer: %s\n", certInfo.Issuer)
fmt.Printf(" Valid from: %s\n", certInfo.NotBefore)
fmt.Printf(" Valid to: %s\n", certInfo.NotAfter)
fmt.Printf(" Domains: %s\n", strings.Join(certInfo.DNSNames, ", "))
// Certificate files
certificatePath := filepath.Join(cli.OutputPath, "certificate.pem")
privateKeyPath := filepath.Join(cli.OutputPath, "private_key.pem")
// Save certificate and private key to files
_, err = public.WriteFile(certificatePath, certificate)
if err != nil {
return "", "", fmt.Errorf("failed to save certificate: %v", err)
}
_, err = public.WriteFile(privateKeyPath, privateKey)
if err != nil {
return "", "", fmt.Errorf("failed to save private key: %v", err)
}
fmt.Printf("Certificate saved to: %s\n", certificatePath)
fmt.Printf("Private key saved to: %s\n", privateKeyPath)
return certificatePath, privateKeyPath, nil
}
/**
* @brief Save certificate to database
* @return error
*/View on GitHub (pinned to fc36c76c05)
Solutions
- Create OutputPath beforehand (mkdir -p) and ensure the running user can write to it
- Pass an absolute, existing --output-path when invoking applyCommand
- Fix the wrapped OS error (permissions, disk space) indicated in the message
- Use a dedicated certs directory owned by the service user
Example fix
// before
cli := &AcmeCLI{Email: e, Domains: d, VerifyType: "http", OutputPath: ""} // writes to relative cwd
// after
out := "/var/lib/acme/certs"
os.MkdirAll(out, 0750)
cli := &AcmeCLI{Email: e, Domains: d, VerifyType: "http", OutputPath: out} Defensive patterns
Strategy: validation
Validate before calling
out := cli.OutputPath
if out == "" { return errors.New("output path must be set") }
if err := os.MkdirAll(out, 0750); err != nil { return err }
if err := unix.Access(out, unix.W_OK); err != nil { return fmt.Errorf("%s not writable: %w", out, err) } Try / catch
if _, _, err := cli.Apply(ctx); err != nil {
if strings.Contains(err.Error(), "failed to save certificate") {
log.Printf("cert write failed for %s: %v; check OutputPath permissions/space", cli.OutputPath, err)
}
return err
} Prevention
- Always pass an absolute, pre-created OutputPath
- Create the output directory at deploy/startup time
- Run the CLI as a user with write access to the output dir (avoid defaulting to root-only cwd)
- Monitor disk space on the volume holding OutputPath
When it happens
Trigger: Apply with OutputPath set to a non-existent or unwritable directory, or OutputPath empty so relative write fails; the WriteFile for certificatePath returns an error.
Common situations: Running the CLI from a cwd without write permission while OutputPath was defaulted; OutputPath directory not created before Apply; read-only container filesystem; disk full.
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 save certificate file: {}
- failed to save private key: %v
- Failed to create directory: {}
- Failed to save private key file: {}
- invalid certificate
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/f2f07c6a7bd7659c.
Report an issue: GitHub.