{"record":{"id":"04150f6aa217ccf1","repo":"Billionmail/BillionMail","slug":"failed-to-hash-postfix-config-v","errorCode":null,"errorMessage":"failed to hash postfix config: %v","messagePattern":"failed to hash postfix config: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/mail_service/certificate.go","lineNumber":342,"sourceCode":"\tfor i, line := range lines {\n\t\tif strings.HasPrefix(line, domain) {\n\t\t\tlines[i] = fmt.Sprintf(\"%s %s %s\", domain, keyPath, certPath)\n\t\t\taddNewLine = false\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif addNewLine {\n\t\tlines = append(lines, fmt.Sprintf(\"%s %s %s\", domain, keyPath, certPath))\n\t}\n\n\tif err := os.WriteFile(c.PostfixSNIPath, []byte(strings.Join(lines, \"\\n\")), 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to write postfix config: %v\", err)\n\t}\n\n\t// Rehash configuration\n\tif _, err := c.dockerApiClient().ExecCommandByName(context.Background(), consts.SERVICES.Postfix, []string{\"postmap\", \"/etc/postfix/conf/vmail_ssl.map\"}, \"root\"); err != nil {\n\t\treturn fmt.Errorf(\"failed to hash postfix config: %v\", err)\n\t}\n\n\treturn nil\n}\n\n// updateDovecotConfig updates Dovecot configuration with new certificate\nfunc (c *Certificate) updateDovecotConfig(csrPem, keyPem string) error {\n\tdovecotConf := c.DovecotSslConf\n\tcontent, err := os.ReadFile(dovecotConf)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read dovecot config: %v\", err)\n\t}\n\n\t// Write certificate and key to files\n\tcertPath := public.AbsPath(filepath.Join(consts.SSL_PATH, \"dovecot.crt\"))\n\tkeyPath := public.AbsPath(filepath.Join(consts.SSL_PATH, \"dovecot.key\"))\n\n\tif err := os.WriteFile(certPath, []byte(csrPem), 0755); err != nil {","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/mail_service/certificate.go#L324-L360","documentation":"After persisting the SNI map, updatePostfixSNIMap execs 'postmap /etc/postfix/conf/vmail_ssl.map' inside the Postfix container to rebuild the .db lookup file, wrapping failure with this message. Without rehashing, Postfix keeps serving the stale SNI map.","triggerScenarios":"The docker exec of postmap fails because the Postfix container is stopped/restarting, the service name in consts.SERVICES.Postfix doesn't match a running container, or the map file isn't visible at /etc/postfix/conf/vmail_ssl.map inside the container.","commonSituations":"Postfix container crashed or mid-restart during cert update; docker API unreachable from the app container; volume mount path mismatch so the map file is absent in the container; wrong service name after a compose rename.","solutions":["Verify the Postfix container is running (docker ps) and restart it if stopped.","Confirm consts.SERVICES.Postfix matches the actual container/service name.","Check the map file exists at /etc/postfix/conf/vmail_ssl.map inside the container (volume mount correct).","Inspect the wrapped exec error/output from ExecCommandByName for the postmap stderr.","Run postmap manually inside the container as a workaround, then retry SetSNI."],"exampleFix":"// before\nif _, err := c.dockerApiClient().ExecCommandByName(context.Background(), consts.SERVICES.Postfix, []string{\"postmap\", \"/etc/postfix/conf/vmail_ssl.map\"}, \"root\"); err != nil {\n    return fmt.Errorf(\"failed to hash postfix config: %v\", err)\n}\n// after\nif _, err := c.dockerApiClient().ExecCommandByName(context.Background(), consts.SERVICES.Postfix, []string{\"postmap\", \"/etc/postfix/conf/vmail_ssl.map\"}, \"root\"); err != nil {\n    return fmt.Errorf(\"failed to hash postfix config (postmap in %s): %w\", consts.SERVICES.Postfix, err)\n}","handlingStrategy":"retry","validationCode":"// before calling SetSNI, ensure the exec target is healthy:\nif !dockerServiceRunning(consts.SERVICES.Postfix) {\n    return fmt.Errorf(\"postfix container %s not running\", consts.SERVICES.Postfix)\n}\n// and that the map is visible in-container:\n// docker exec <postfix> test -f /etc/postfix/conf/vmail_ssl.map","typeGuard":null,"tryCatchPattern":"err := svc.SetSNI(ctx, domain)\nif err != nil && strings.Contains(err.Error(), \"failed to hash postfix config\") {\n    log.Printf(\"postmap exec failed — is the postfix container up? %v\", err)\n    time.Sleep(5 * time.Second)\n    err = svc.SetSNI(ctx, domain) // retry once container healthy\n}","preventionTips":["Add a healthcheck to the Postfix container and gate cert updates on it.","Verify consts.SERVICES.Postfix matches the compose service name after renames.","Confirm /etc/postfix/conf volume mapping includes vmail_ssl.map.","Handle transient docker API errors with bounded retries/backoff.","Run postmap after any out-of-band edits to vmail_ssl.map."],"tags":["docker","postfix","sni","exec","container"],"backgroundTag":"docker-exec-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"}