Billionmail/BillionMail · critical
failed to read backup file %s: %v
Error message
failed to read backup file %s: %v
What it means
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'.
Source
Thrown at core/internal/service/multi_ip_domain/config_manager.go:112
return nil, fmt.Errorf("failed to create backup for %s: %v", file, err)
}
g.Log().Debugf(ctx, "Created backup for %s at %s", file, backupPath)
backups[file] = backupPath
}
}
return backups, nil
}
// rollback Roll back configurations
func (m *ConfigManager) rollback(ctx context.Context, backups map[string]string) error {
var allErrors []string
for file, backup := range backups {
if gfile.Exists(backup) {
g.Log().Infof(ctx, "Rolling back %s from %s", file, backup)
content, err := ioutil.ReadFile(backup)
if err != nil {
err = fmt.Errorf("failed to read backup file %s: %v", backup, err)
allErrors = append(allErrors, err.Error())
continue
}
if err := ioutil.WriteFile(file, content, 0644); err != nil {
err = fmt.Errorf("failed to rollback file %s: %v", file, err)
allErrors = append(allErrors, err.Error())
}
}
}
if len(allErrors) > 0 {
return fmt.Errorf("%s", strings.Join(allErrors, "; "))
}
return nil
}
// cleanupBackups Clean up backup files
func (m *ConfigManager) cleanupBackups(ctx context.Context, backups map[string]string) {View on GitHub (pinned to fc36c76c05)
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.
Defensive patterns
Strategy: try-catch
Try / catch
if err := mgr.ApplyConfigsWithRollback(ctx, configs); err != nil {
if strings.Contains(err.Error(), "failed to read backup file") {
// enumerate *.backup.* files and restore manually with elevated permissions
bks, _ := filepath.Glob(multi_ip_domain.PostfixMainCfPath + ".backup.*")
_ = bks
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- failed to create backup for %s: %v
- failed to rollback file %s: %v
- error reading project configuration file: %v
- error writing project configuration file: %v
- error writing knowledge base file: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/d8ba45a8df1f76d9.
Report an issue: GitHub.