Billionmail/BillionMail · error

failed to create backup: %v

Error message

failed to create backup: %v

What it means

ApplyConfigsWithRollback wraps any failure from createBackups with 'failed to create backup'. Backups of postfix main.cf and master.cf are mandatory before applying new configs; if a backup can't be made the whole apply is aborted to guarantee rollback capability.

Source

Thrown at core/internal/service/multi_ip_domain/config_manager.go:62

func NewConfigManager(ctx context.Context) (*ConfigManager, error) {
	manager := &ConfigManager{
		ctx:             ctx,
		masterCfEntries: []string{},
		fileLocker:      gmutex.New(),
	}

	return manager, nil
}

// ApplyConfigsWithRollback Apply configurations and rollback on failure
func (m *ConfigManager) ApplyConfigsWithRollback(ctx context.Context, configs []map[string]interface{}) error {

	m.fileLocker.Lock()
	defer m.fileLocker.Unlock()

	backups, err := m.createBackups(ctx)
	if err != nil {
		return fmt.Errorf("failed to create backup: %v", err)
	}

	// Apply configurations
	if err := m.applyConfigs(ctx, configs); err != nil {

		g.Log().Debugf(ctx, "Failed to apply configurations, rolling back... Error: %v", err)
		if rollbackErr := m.rollback(ctx, backups); rollbackErr != nil {
			return fmt.Errorf("failed to apply configurations: %v, rollback also failed: %v", err, rollbackErr)
		}
		return fmt.Errorf("failed to apply configurations, but rollback succeeded: %v", err)
	}

	m.cleanupBackups(ctx, backups)
	return nil
}

// createBackups Create backups for Postfix's main.cf and master.cf
func (m *ConfigManager) createBackups(ctx context.Context) (map[string]string, error) {

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Check filesystem permissions on the postfix config files and directory (process must read the files and write alongside them)
  2. Free disk space — backup write failures are commonly ENOSPC
  3. Verify PostfixMainCfPath/PostfixMasterCfPath point at real files and the mount is writable
  4. Run the service with sufficient privileges or pre-grant write access to the config directory
Defensive patterns

Strategy: validation

Validate before calling

for _, f := range []string{PostfixMainCfPath, PostfixMasterCfPath} {
    if fi, err := os.Stat(f); err != nil || !fi.Mode().IsRegular() {
        return fmt.Errorf("cannot back up %s: %v", f, err)
    }
    if err := unix.Access(filepath.Dir(f), unix.W_OK); err != nil {
        return fmt.Errorf("config dir not writable: %v", err)
    }
}
if free, _ := diskFree("/etc/postfix"); free < 10*1024*1024 { return errors.New("low disk space") }

Try / catch

err := manager.ApplyConfigsWithRollback(ctx, configs)
if err != nil && strings.HasPrefix(err.Error(), "failed to create backup") {
    // environment problem: check permissions/disk, alert ops, do not retry blindly
    alertOps(err)
}

Prevention

When it happens

Trigger: ioutil.ReadFile fails on an existing PostfixMainCfPath/PostfixMasterCfPath (permissions, race-deleted file) or ioutil.WriteFile of the .backup.<nanotimestamp> file fails (disk full, read-only mount, permission denied on the config directory).

Common situations: Container running without root/file permissions on /etc/postfix; disk full on the host; configs mounted read-only in Docker; postfix config paths misconfigured to nonexistent locations; SELinux/AppArmor denying writes.

Related errors


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