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

  1. Inspect the wrapped %v error and fix permissions on the .backup.<nano> files (chmod/chown so the process user can read).
  2. Manually restore the configs: copy the backup file content over main.cf/master.cf yourself, then re-run the operation.
  3. Disable or reschedule any cron/job that deletes *.backup.* files from conf/postfix.
  4. 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

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


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/d8ba45a8df1f76d9. Report an issue: GitHub.