{"record":{"id":"75414c00e8f17f48","repo":"Billionmail/BillionMail","slug":"failed-to-write-postfix-master-config-v","errorCode":null,"errorMessage":"failed to write postfix master config: %v","messagePattern":"failed to write postfix master config: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/mail_service/certificate.go","lineNumber":181,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read postfix master config: %v\", err)\n\t}\n\n\tcontent, err = gregex.ReplaceString(`\\n*#\\s*-o\\s+smtpd_tls_auth_only=yes`, \"\\n  -o smtpd_tls_auth_only=yes\", content)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to update postfix master config: %v\", err)\n\t}\n\n\tcontent, err = gregex.ReplaceString(`\\n*#\\s*-o\\s+smtpd_tls_wrappermode=yes`, \"\\\\n  -o smtpd_tls_wrappermode=yes\", content)\n\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to update postfix master config: %v\", err)\n\t}\n\n\t// Update Postfix Master configuration\n\tif err := os.WriteFile(c.PostfixMasterConf, []byte(content), 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to write postfix master config: %v\", err)\n\t}\n\n\treturn nil\n}\n\n// SetDovecotSSL configures SSL certificate for Dovecot\nfunc (c *Certificate) SetDovecotSSL(csrPem, keyPem string) error {\n\t// Validate certificate data\n\tif err := c.verifyCertificate(csrPem, keyPem); err != nil {\n\t\treturn err\n\t}\n\n\t// Update Dovecot configuration\n\tif err := c.updateDovecotConfig(csrPem, keyPem); err != nil {\n\t\treturn err\n\t}\n\n\t// Restart Dovecot service","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/mail_service/certificate.go#L163-L199","documentation":"Raised in SetPostfixMasterSSL when os.WriteFile fails to persist the edited Postfix master.cf (c.PostfixMasterConf path) after the smtpd_tls_auth_only/smtpd_tls_wrappermode substitutions succeeded. Typical causes: permission denial on the Postfix config path or a read-only filesystem; the SSL enable flow aborts before service restart.","triggerScenarios":"os.WriteFile to c.PostfixMasterConf fails: read-only filesystem, missing directory, or insufficient permissions (app not running as root).","commonSituations":"App container without write access to /etc/postfix; master.cf mounted read-only in Docker; disk full on the config volume.","solutions":["Run the service with privileges to write master.cf (root or CAP_DAC_OVERRIDE in container)","Ensure the postfix config volume is mounted read-write","Check filesystem free space and mount flags (ro vs rw)","Consider writing atomically (temp file + rename) and matching mode 0644 typical for master.cf instead of 0755"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"cfPath := consts.POSTFIX_MASTER_CONF\nif err := os.MkdirAll(filepath.Dir(cfPath), 0755); err != nil { return err }\ntest, err := os.OpenFile(cfPath, os.O_WRONLY, 0)\nif err != nil {\n    return fmt.Errorf(\"cannot write %s: %w (need root or rw mount)\", cfPath, err)\n}\ntest.Close()","typeGuard":null,"tryCatchPattern":"if err := certService.SetPostfixMasterSSL(); err != nil {\n    if strings.Contains(err.Error(), \"failed to write postfix master config\") {\n        if isReadOnly(strings Dir(cfPath)) { remountOrRelaunchWithWriteAccess() }\n        return err\n    }\n    return err\n}","preventionTips":["Run the TLS automation as root or with a rw-mounted /etc/postfix","Check df/disk space before config writes","Write atomically (temp file + os.Rename) and use mode 0644"],"tags":["postfix","file-write","permissions","tls"],"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"}