{"record":{"id":"da17d851fa9ae9b1","repo":"Billionmail/BillionMail","slug":"failed-to-save-private-key-file","errorCode":null,"errorMessage":"Failed to save private key file: {}","messagePattern":"Failed to save private key file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/acme/acme.go","lineNumber":489,"sourceCode":"\t\tif !public.FileExists(savePath) {\n\t\t\terr = os.MkdirAll(savePath, 0750)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", \"\", errors.New(public.LangCtx(ctx, \"Failed to create directory: {}\", err.Error()))\n\t\t\t}\n\t\t}\n\n\t\t// Save certificate and private key files\n\t\tcertificateFile := filepath.Join(savePath, \"certificate.pem\")\n\t\tprivateKeyFile := filepath.Join(savePath, \"private_key.pem\")\n\n\t\t_, err = public.WriteFile(certificateFile, string(certificates.Certificate))\n\t\tif err != nil {\n\t\t\treturn \"\", \"\", errors.New(public.LangCtx(ctx, \"Failed to save certificate file: {}\", err.Error()))\n\t\t}\n\n\t\t_, err = public.WriteFile(privateKeyFile, string(certificates.PrivateKey))\n\t\tif err != nil {\n\t\t\treturn \"\", \"\", errors.New(public.LangCtx(ctx, \"Failed to save private key file: {}\", err.Error()))\n\t\t}\n\t}\n\n\t// Return certificate\n\treturn string(certificates.Certificate), string(certificates.PrivateKey), nil\n}\n\ntype CertInfo v1.CertInfo\n\n/**\n * @description: Get certificate information\n * @param {string} certificateStr Certificate string\n * @return {CertInfo} Certificate information\n */\nfunc GetCertInfo(certificateStr string) CertInfo {\n\tcertInfo := CertInfo{}\n\tblock, _ := pem.Decode([]byte(certificateStr))\n\tif block == nil {","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/acme/acme.go#L471-L507","documentation":"Thrown in ApplySSLWithExistingServer when public.WriteFile fails to persist private_key.pem into savePath, after certificate.pem was written successfully. It wraps the raw OS error so the actual cause (permissions, disk full, path issues) is in the message.","triggerScenarios":"ApplySSLWithExistingServer calls public.WriteFile(privateKeyFile, string(certificates.PrivateKey)) and the OS write fails — typically same causes as the certificate write: permissions, full disk, directory removed mid-operation.","commonSituations":"Save directory ownership changed between writes by an external sync; quota exceeded mid-write; disk filled up by the preceding certificate write in a constrained container.","solutions":["Read the embedded OS error and fix the filesystem condition (permissions, disk space)","Verify the process can create files in savePath (touch a test file as the service user)","Free disk space / raise quota if 'no space left on device' is reported","Ensure nothing removes or chmods savePath between the certificate and key writes"],"exampleFix":"// before\n// cert dir writable only by root; service runs as mailuser\n_, _, err = svc.ApplySSLWithExistingServer(ctx, d, keyType, c, k, \"/etc/ssl/private\")\n// after\nos.Chown(\"/etc/ssl/private/mailuser\", uid, gid) // or use a dedicated dir owned by the service user\n_, _, err = svc.ApplySSLWithExistingServer(ctx, d, keyType, c, k, \"/etc/ssl/private/mailuser\")","handlingStrategy":"validation","validationCode":"if err := os.MkdirAll(savePath, 0750); err != nil { return err }\nif err := unix.Access(savePath, unix.W_OK); err != nil { return fmt.Errorf(\"%s not writable: %w\", savePath, err) }\n// ensure free space for both files\nif st, err := os.Statfs(savePath); err == nil && st.Bavail*uint64(st.Bsize) < 64*1024 { return errors.New(\"insufficient space for key material\") }","typeGuard":null,"tryCatchPattern":"if _, _, err := svc.ApplySSLWithExistingServer(ctx, d, kt, c, k, savePath); err != nil {\n    if strings.Contains(err.Error(), \"private key\") {\n        log.Printf(\"key persistence failed for %s: %v\", savePath, err)\n        // cert.pem may exist; clean up partial state before retry\n        os.Remove(filepath.Join(savePath, \"certificate.pem\"))\n    }\n    return err\n}","preventionTips":["Verify writability of savePath as the service user before issuance","Monitor disk usage; key writes fail on full volumes","Avoid concurrent jobs chmod/chown the directory mid-write","Use restrictive-but-owned dirs (0750, service user) for key material"],"tags":["filesystem","ssl","private-key","file-write"],"backgroundTag":"file-write-permission-denied","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}