{"record":{"id":"053b0feba2a6a122","repo":"Billionmail/BillionMail","slug":"failed-to-create-directory","errorCode":null,"errorMessage":"Failed to create directory: {}","messagePattern":"Failed to create directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/acme/acme.go","lineNumber":474,"sourceCode":"\t// Submit application\n\trequest := certificate.ObtainRequest{\n\t\tDomains: domains,\n\t\tBundle:  true,\n\t}\n\n\t// Get certificate\n\tcertificates, err := client.Certificate.Obtain(request)\n\tif err != nil {\n\t\treturn \"\", \"\", errors.New(public.LangCtx(ctx, \"Failed to apply for SSL certificate: {}\", err.Error()))\n\t}\n\n\t// Save certificate files if path is provided\n\tif savePath != \"\" {\n\t\t// Create directory if it doesn't exist\n\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","sourceCodeStart":456,"sourceCodeEnd":492,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/acme/acme.go#L456-L492","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nsavePath := \"/etc/letsencrypt/live/example.com\" // parent may not exist, mounted ro\n_, _, err := svc.ApplySSLWithExistingServer(ctx, domains, keyType, cert, key, savePath)\n// after\nif err := os.MkdirAll(\"/etc/letsencrypt/live\", 0750); err != nil { log.Fatal(err) }\n_, _, err := svc.ApplySSLWithExistingServer(ctx, domains, keyType, cert, key, savePath)","handlingStrategy":"validation","validationCode":"info, err := os.Stat(savePath)\nif err == nil && !info.IsDir() { return fmt.Errorf(\"%s is a file, not a directory\", savePath) }\nif os.IsNotExist(err) {\n    if err := os.MkdirAll(filepath.Dir(savePath), 0750); err != nil {\n        return fmt.Errorf(\"cannot create parent of %s: %w\", savePath, err)\n    }\n}\nif err := unix.Access(filepath.Dir(savePath), unix.W_OK); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if _, _, err := svc.ApplySSLWithExistingServer(ctx, d, kt, c, k, savePath); err != nil {\n    if strings.Contains(err.Error(), \"mkdir\") {\n        log.Printf(\"cert dir issue for %s: %v\", savePath, err)\n        os.MkdirAll(savePath, 0750) // attempt recovery\n    }\n}","preventionTips":["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"],"tags":["filesystem","ssl","certificate","mkdir"],"backgroundTag":"mkdir-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"}