{"record":{"id":"0b2aa4fc3b7e5748","repo":"Billionmail/BillionMail","slug":"failed-to-write-dkim-signing-config-v","errorCode":null,"errorMessage":"failed to write DKIM signing config: %v","messagePattern":"failed to write DKIM signing config: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/domains/domains.go","lineNumber":973,"sourceCode":"#%s_DKIM_END\n`, d.Domain, d.Domain, d.Domain, d.Domain, d.Domain)\n\t\tallSignConfBlocks.WriteString(signConf)\n\t}\n\n\t// 3. Construct the final dkim_signing.conf content\n\tsignConfPath := public.AbsPath(filepath.Join(consts.RSPAMD_LOCAL_D_PATH, \"dkim_signing.conf\"))\n\tfinalSignContent := fmt.Sprintf(`sign_headers = \"from:sender:reply-to:subject:date:message-id:to:cc:mime-version:content-type:content-transfer-encoding:content-language:resent-to:resent-cc:resent-from:resent-sender:resent-message-id:in-reply-to:references:list-id:list-help:list-owner:list-unsubscribe:list-subscribe:list-post:list-unsubscribe-post:disposition-notification-to:disposition-notification-options:original-recipient:openpgp:autocrypt\";\n\ndomain {\n#BT_DOMAIN_DKIM_BEGIN\n%s\n#BT_DOMAIN_DKIM_END\n}`, allSignConfBlocks.String())\n\n\t// 4. Write the new content to the file, overwriting the old one\n\t_, err = public.WriteFile(signConfPath, finalSignContent)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to write DKIM signing config: %v\", err)\n\t}\n\n\t// 5. Ensure correct file permissions\n\terr = filepath.Walk(filepath.Join(public.AbsPath(consts.RSPAMD_LIB_PATH), \"dkim\"), func(path string, info os.FileInfo, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif info.IsDir() {\n\t\t\treturn os.Chmod(path, 0755)\n\t\t}\n\t\tif strings.HasSuffix(path, \".private\") || strings.HasSuffix(path, \".pub\") {\n\t\t\treturn os.Chmod(path, 0644)\n\t\t}\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to change DKIM file permissions: %v\", err)\n\t}","sourceCodeStart":955,"sourceCodeEnd":991,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/domains/domains.go#L955-L991","documentation":"RepairDKIMSigningConfig regenerates the Rspamd DKIM signing configuration block and overwrites the signing config file via public.WriteFile. This error wraps any failure from that write, meaning the new DKIM config content could not be persisted to disk.","triggerScenarios":"public.WriteFile(signConfPath, finalSignContent) returns non-nil: the signing config path is unwritable (permissions), the directory is missing, the filesystem is full/read-only, or the path resolves outside the container's mounted volume.","commonSituations":"Rspamd conf directory not bind-mounted into the app container; running the process as non-root without write access to /etc/rspamd or the RSPAMD_LIB_PATH volume; disk full on host; SELinux/AppArmor denying writes.","solutions":["Verify the signing config path (derived from RSPAMD_LIB_PATH / rspamd conf dir) exists and is writable by the process user","Check disk space (df -h) and filesystem mount status (mount ro?)","Ensure the rspamd conf volume is mounted and the process runs with sufficient privileges (or chown the conf dir)","Inspect the wrapped %v error for the underlying OS cause (e.g. permission denied vs no such file)"],"exampleFix":"// before\n_, err = public.WriteFile(signConfPath, finalSignContent)\nif err != nil {\n\treturn fmt.Errorf(\"failed to write DKIM signing config: %v\", err)\n}\n// after\nif err := os.MkdirAll(filepath.Dir(signConfPath), 0755); err != nil {\n\treturn fmt.Errorf(\"failed to prepare dkim conf dir: %v\", err)\n}\n_, err = public.WriteFile(signConfPath, finalSignContent)\nif err != nil {\n\treturn fmt.Errorf(\"failed to write DKIM signing config %s: %v\", signConfPath, err)\n}","handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(filepath.Dir(signConfPath)); err != nil || !fi.IsDir() {\n\treturn fmt.Errorf(\"dkim conf dir missing: %s\", filepath.Dir(signConfPath))\n}\nif f, err := os.OpenFile(signConfPath, os.O_WRONLY, 0644); err != nil {\n\treturn fmt.Errorf(\"signing config not writable: %v\", err)\n} else {\n\tf.Close()\n}","typeGuard":null,"tryCatchPattern":"err := RepairDKIMSigningConfig(ctx)\nif err != nil && strings.HasPrefix(err.Error(), \"failed to write DKIM signing config\") {\n\tg.Log().Errorf(ctx, \"check rspamd conf mount/permissions: %v\", err)\n}","preventionTips":["Bind-mount the rspamd conf directory read-write into the app container","Run the app as a user with write access to the conf dir","Monitor disk space on the conf volume","Include the failing path in wrapped error messages"],"tags":["filesystem","dkim","rspamd","write-failure"],"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-12T22:17:10.623Z"}