{"record":{"id":"44b6ed22557d105e","repo":"Billionmail/BillionMail","slug":"failed-to-read-file-s-v","errorCode":null,"errorMessage":"failed to read file %s: %v","messagePattern":"failed to read file (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/multi_ip_domain/config_manager.go","lineNumber":89,"sourceCode":"\t\t}\n\t\treturn fmt.Errorf(\"failed to apply configurations, but rollback succeeded: %v\", err)\n\t}\n\n\tm.cleanupBackups(ctx, backups)\n\treturn nil\n}\n\n// createBackups Create backups for Postfix's main.cf and master.cf\nfunc (m *ConfigManager) createBackups(ctx context.Context) (map[string]string, error) {\n\tbackups := make(map[string]string)\n\n\tfiles := []string{PostfixMainCfPath, PostfixMasterCfPath}\n\n\tfor _, file := range files {\n\t\tif gfile.Exists(file) {\n\t\t\tcontent, err := ioutil.ReadFile(file)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to read file %s: %v\", file, err)\n\t\t\t}\n\n\t\t\tbackupPath := fmt.Sprintf(\"%s.backup.%d\", file, time.Now().UnixNano())\n\t\t\tif err := ioutil.WriteFile(backupPath, content, 0644); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to create backup for %s: %v\", file, err)\n\t\t\t}\n\t\t\tg.Log().Debugf(ctx, \"Created backup for %s at %s\", file, backupPath)\n\t\t\tbackups[file] = backupPath\n\t\t}\n\t}\n\n\treturn backups, nil\n}\n\n// rollback Roll back configurations\nfunc (m *ConfigManager) rollback(ctx context.Context, backups map[string]string) error {\n\tvar allErrors []string\n\tfor file, backup := range backups {","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/multi_ip_domain/config_manager.go#L71-L107","documentation":"createBackups reads PostfixMainCfPath and PostfixMasterCfPath to snapshot them before config changes; this error wraps ioutil.ReadFile failure for one of those files and aborts the backup (and thus the whole ApplyConfigsWithRollback run, via the 'failed to create backup' wrapper).","triggerScenarios":"ioutil.ReadFile(file) fails on an existing file listed in files — typically EACCES (process lacks read permission), ENOENT via race (file deleted between gfile.Exists and ReadFile), or EISDIR/IO error.","commonSituations":"Running in a container without postfix config mounted or with restricted permissions; path constants pointing to the wrong location for the deployment; file removed concurrently by another tool; SELinux denials.","solutions":["Verify the file exists at the configured path constant and the process can read it (ls -l, check uid of the service)","Fix permissions or run the service with access to /etc/postfix","Re-check path constants PostfixMainCfPath/PostfixMasterCfPath match the actual deployment layout","Handle ENOENT gracefully — if the file is optional, skip backup for it instead of failing the whole apply"],"exampleFix":"// before\ncontent, err := ioutil.ReadFile(file)\nif err != nil {\n    return nil, fmt.Errorf(\"failed to read file %s: %v\", file, err)\n}\n// after\ncontent, err := ioutil.ReadFile(file)\nif err != nil {\n    if os.IsNotExist(err) {\n        continue // nothing to back up for this file\n    }\n    return nil, fmt.Errorf(\"failed to read file %s: %v\", file, err)\n}","handlingStrategy":"validation","validationCode":"func backupable(path string) error {\n    fi, err := os.Stat(path)\n    if err != nil { return err }\n    if !fi.Mode().IsRegular() { return fmt.Errorf(\"%s is not a regular file\", path) }\n    f, err := os.Open(path)\n    if err != nil { return err }\n    return f.Close()\n}\n// run for both PostfixMainCfPath and PostfixMasterCfPath before applying","typeGuard":null,"tryCatchPattern":"err := manager.ApplyConfigsWithRollback(ctx, configs)\nif err != nil {\n    var pathErr *fs.PathError\n    if errors.As(err, &pathErr) && (errors.Is(pathErr.Err, fs.ErrPermission) || errors.Is(pathErr.Err, fs.ErrNotExist)) {\n        // fix deployment/permissions before retrying\n        reportMisconfiguration(pathErr)\n    }\n}","preventionTips":["Grant the service read permission on /etc/postfix configs","Verify path constants match the container/deployment layout","Don't delete postfix configs concurrently with backup operations","Skip (rather than fail) backup for legitimately absent optional files"],"tags":["filesystem","permissions","postfix","backup"],"backgroundTag":"file-read-failed","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"}