{"record":{"id":"d8ba45a8df1f76d9","repo":"Billionmail/BillionMail","slug":"failed-to-read-backup-file-s-v","errorCode":null,"errorMessage":"failed to read backup file %s: %v","messagePattern":"failed to read backup file (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"core/internal/service/multi_ip_domain/config_manager.go","lineNumber":112,"sourceCode":"\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 {\n\t\tif gfile.Exists(backup) {\n\t\t\tg.Log().Infof(ctx, \"Rolling back %s from %s\", file, backup)\n\t\t\tcontent, err := ioutil.ReadFile(backup)\n\t\t\tif err != nil {\n\t\t\t\terr = fmt.Errorf(\"failed to read backup file %s: %v\", backup, err)\n\t\t\t\tallErrors = append(allErrors, err.Error())\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif err := ioutil.WriteFile(file, content, 0644); err != nil {\n\t\t\t\terr = fmt.Errorf(\"failed to rollback file %s: %v\", file, err)\n\t\t\t\tallErrors = append(allErrors, err.Error())\n\t\t\t}\n\t\t}\n\t}\n\tif len(allErrors) > 0 {\n\t\treturn fmt.Errorf(\"%s\", strings.Join(allErrors, \"; \"))\n\t}\n\treturn nil\n}\n\n// cleanupBackups Clean up backup files\nfunc (m *ConfigManager) cleanupBackups(ctx context.Context, backups map[string]string) {","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/multi_ip_domain/config_manager.go#L94-L130","documentation":"rollback restores original Postfix configs from the backup files created by createBackups. When ioutil.ReadFile cannot read a backup file, the error is collected (not returned immediately), the file is skipped, and rollback continues with the other backups. A non-empty aggregate error is returned at the end, causing ApplyConfigsWithRollback to report 'rollback also failed'.","triggerScenarios":"During rollback, gfile.Exists(backup) is true but ioutil.ReadFile(backup) fails — e.g. permissions changed after creation, file truncated/deleted between the Exists check and the read, or an I/O error on the volume.","commonSituations":"Backup files created with 0644 but the reader runs under a different user; NFS/network volume hiccup; external cleanup job deleting *.backup.* files mid-rollback; disk error.","solutions":["Inspect the wrapped %v error and fix permissions on the .backup.<nano> files (chmod/chown so the process user can read).","Manually restore the configs: copy the backup file content over main.cf/master.cf yourself, then re-run the operation.","Disable or reschedule any cron/job that deletes *.backup.* files from conf/postfix.","Check volume health (dmesg for I/O errors) and remount/replace the failing volume."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := mgr.ApplyConfigsWithRollback(ctx, configs); err != nil {\n\tif strings.Contains(err.Error(), \"failed to read backup file\") {\n\t\t// enumerate *.backup.* files and restore manually with elevated permissions\n\t\tbks, _ := filepath.Glob(multi_ip_domain.PostfixMainCfPath + \".backup.*\")\n\t\t_ = bks\n\t}\n}","preventionTips":["Never schedule deletion of *.backup.* files while an apply can be in flight.","Keep backup and live files under the same ownership and umask.","Avoid NFS/network volumes for config directories.","Check logs for 'Rolling back %s from %s' to identify which backup failed."],"tags":["filesystem","permissions","rollback","backup","go"],"backgroundTag":"rollback-restore-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"}