Billionmail/BillionMail · error
Failed to create directory: {}
Error message
Failed to create directory: {} What it means
This error is thrown in ApplySSLWithExistingServer when os.MkdirAll fails to create the savePath directory that will hold the issued certificate files. It wraps the underlying OS error (permission denied, path is a file, parent missing on read-only FS, etc.) via LangCtx so it is localized before being returned to callers like Apply or StartRenew.
Source
Thrown at core/internal/service/acme/acme.go:474
// Submit application
request := certificate.ObtainRequest{
Domains: domains,
Bundle: true,
}
// Get certificate
certificates, err := client.Certificate.Obtain(request)
if err != nil {
return "", "", errors.New(public.LangCtx(ctx, "Failed to apply for SSL certificate: {}", err.Error()))
}
// Save certificate files if path is provided
if savePath != "" {
// Create directory if it doesn't exist
if !public.FileExists(savePath) {
err = os.MkdirAll(savePath, 0750)
if err != nil {
return "", "", errors.New(public.LangCtx(ctx, "Failed to create directory: {}", err.Error()))
}
}
// Save certificate and private key files
certificateFile := filepath.Join(savePath, "certificate.pem")
privateKeyFile := filepath.Join(savePath, "private_key.pem")
_, err = public.WriteFile(certificateFile, string(certificates.Certificate))
if err != nil {
return "", "", errors.New(public.LangCtx(ctx, "Failed to save certificate file: {}", err.Error()))
}
_, err = public.WriteFile(privateKeyFile, string(certificates.PrivateKey))
if err != nil {
return "", "", errors.New(public.LangCtx(ctx, "Failed to save private key file: {}", err.Error()))
}
}
View on GitHub (pinned to fc36c76c05)
Solutions
- Check the wrapped OS error in the message (permission denied, not a directory, read-only file system) and fix the corresponding filesystem condition
- Ensure the parent directory of savePath exists and is writable by the process user (chown/chmod or mkdir -p manually)
- Verify savePath is a directory path, not a path to an existing file; rename or remove the conflicting file
- In Docker, mount the certificate volume read-write instead of read-only
Example fix
// before
savePath := "/etc/letsencrypt/live/example.com" // parent may not exist, mounted ro
_, _, err := svc.ApplySSLWithExistingServer(ctx, domains, keyType, cert, key, savePath)
// after
if err := os.MkdirAll("/etc/letsencrypt/live", 0750); err != nil { log.Fatal(err) }
_, _, err := svc.ApplySSLWithExistingServer(ctx, domains, keyType, cert, key, savePath) Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(savePath)
if err == nil && !info.IsDir() { return fmt.Errorf("%s is a file, not a directory", savePath) }
if os.IsNotExist(err) {
if err := os.MkdirAll(filepath.Dir(savePath), 0750); err != nil {
return fmt.Errorf("cannot create parent of %s: %w", savePath, err)
}
}
if err := unix.Access(filepath.Dir(savePath), unix.W_OK); err != nil { return err } Try / catch
if _, _, err := svc.ApplySSLWithExistingServer(ctx, d, kt, c, k, savePath); err != nil {
if strings.Contains(err.Error(), "mkdir") {
log.Printf("cert dir issue for %s: %v", savePath, err)
os.MkdirAll(savePath, 0750) // attempt recovery
}
} Prevention
- Provision the cert directory (and ownership) at deploy time, not at issuance time
- Mount certificate volumes read-write in Docker
- Never point savePath at an existing file path
- Run the service under a user that owns the cert directory
When it happens
Trigger: Calling ApplySSLWithExistingServer with a non-empty savePath that does not exist, where os.MkdirAll(savePath, 0750) fails — e.g. parent directory is missing on a read-only filesystem, a file already exists at savePath, or the process lacks write permission on the parent.
Common situations: Deployments where the configured cert save path points into a volume not mounted or mounted read-only; savePath accidentally set to an existing file; container running as non-root user without ownership of /etc/letsencrypt-like directories.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- Failed to save certificate file: {}
- fail to set ssl: %w
- Failed to save private key file: {}
- failed to save certificate: %v
- certificate not found in database: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/053b0feba2a6a122.
Report an issue: GitHub.