{"record":{"id":"973cc93700b22baf","repo":"Billionmail/BillionMail","slug":"failed-to-create-domain-directory-v","errorCode":null,"errorMessage":"failed to create domain directory: %v","messagePattern":"failed to create domain directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/mail_service/certificate.go","lineNumber":289,"sourceCode":"\t// Update Postfix virtual mail configuration\n\tif err := c.updatePostfixVMailConfig(domain, csrPem, keyPem); err != nil {\n\t\treturn err\n\t}\n\n\t// Restart Postfix service\n\tif err := c.restartPostfix(); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// updatePostfixVMailConfig updates Postfix virtual mail configuration\nfunc (c *Certificate) updatePostfixVMailConfig(domain, csrPem, keyPem string) error {\n\t// Ensure domain directory exists\n\tdomainDir := filepath.Join(consts.SSL_PATH, domain)\n\tif err := os.MkdirAll(domainDir, 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to create domain directory: %v\", err)\n\t}\n\n\tvmailCert := filepath.Join(domainDir, \"fullchain.pem\")\n\tvmailKey := filepath.Join(domainDir, \"privkey.pem\")\n\n\t// Write certificate and key to files\n\tif err := os.WriteFile(vmailCert, []byte(csrPem), 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to write certificate file: %v\", err)\n\t}\n\n\tif err := os.WriteFile(vmailKey, []byte(keyPem), 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to write key file: %v\", err)\n\t}\n\n\t// Create SNI mapping table\n\tif err := c.updatePostfixSNIMap(public.FormatMX(domain), vmailCert, vmailKey); err != nil {\n\t\treturn fmt.Errorf(\"failed to update SNI map: %v\", err)\n\t}","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/mail_service/certificate.go#L271-L307","documentation":"updatePostfixVMailConfig creates a per-domain directory under SSL_PATH (os.MkdirAll) before writing fullchain.pem/privkey.pem. If MkdirAll fails, the OS error is wrapped with this message. Per-domain SNI certs cannot be stored without this directory.","triggerScenarios":"SetSNI or SetPostfixVMailCert called with a domain whose directory path cannot be created — SSL_PATH missing/unwritable, invalid characters in domain used as path segment, or read-only filesystem.","commonSituations":"Wildcard names or user-supplied domains containing '/' or '..' causing bad path segments; SSL volume unmounted; parent directory owned by root; read-only container FS.","solutions":["Sanitize/validate the domain before using it as a directory name (reject '/', '..', empty).","Ensure SSL_PATH exists and is writable by the process user.","Check the wrapped OS error for the exact errno and fix the mount/permission accordingly.","Verify the Docker volume backing SSL_PATH is present and writable.","Retry SetSNI and confirm the domain directory now exists."],"exampleFix":"// before\ndomainDir := filepath.Join(consts.SSL_PATH, domain)\nif err := os.MkdirAll(domainDir, 0755); err != nil {\n    return fmt.Errorf(\"failed to create domain directory: %v\", err)\n}\n// after\nif strings.ContainsAny(domain, \"/\\\\\") || strings.Contains(domain, \"..\") {\n    return fmt.Errorf(\"invalid domain for ssl directory: %q\", domain)\n}\ndomainDir := filepath.Join(consts.SSL_PATH, domain)\nif err := os.MkdirAll(domainDir, 0755); err != nil {\n    return fmt.Errorf(\"failed to create domain directory %s: %w\", domainDir, err)\n}","handlingStrategy":"validation","validationCode":"func validDomainForPath(d string) bool {\n    if d == \"\" || strings.ContainsAny(d, \"/\\\\\") || strings.Contains(d, \"..\") {\n        return false\n    }\n    return true\n}\n// before calling:\nif !validDomainForPath(domain) { return fmt.Errorf(\"invalid domain: %q\", domain) }\nif err := os.MkdirAll(consts.SSL_PATH, 0755); err != nil { return err }","typeGuard":null,"tryCatchPattern":"err := svc.SetSNI(ctx, domain)\nif err != nil && strings.Contains(err.Error(), \"failed to create domain directory\") {\n    log.Printf(\"validate domain characters and SSL_PATH writability: %v\", err)\n}","preventionTips":["Validate domains against a strict regex before using them as path segments.","Pre-create and chown SSL_PATH at deployment time.","Ensure the SSL volume is mounted before the app starts (depends_on/healthchecks).","Reject wildcard names ('*.example.com') or sanitize them before path use."],"tags":["filesystem","ssl-certificate","sni","directory-creation","domain"],"backgroundTag":"directory-creation-failed","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"}