vitessio/vitess · critical

could not move %v to %v: %v

Error message

could not move %v to %v: %v

What it means

After successfully backing up the old my.cnf to my.cnf.previous, RefreshConfig failed to rename the freshly generated temp config into place. This leaves the config dir in a state where my.cnf is absent and the new config remains as the temp file (backup already succeeded).

Source

Thrown at go/vt/mysqlctl/mysqld.go:1600

	}
	updated, err := os.ReadFile(f.Name())
	if err != nil {
		return fmt.Errorf("could not read updated file %v: %v", f.Name(), err)
	}

	if bytes.Equal(existing, updated) {
		log.Info("No changes to my.cnf. Continuing.")
		return nil
	}

	backupPath := cnf.Path + ".previous"
	err = os.Rename(cnf.Path, backupPath)
	if err != nil {
		return fmt.Errorf("could not back up existing %v: %v", cnf.Path, err)
	}
	err = os.Rename(f.Name(), cnf.Path)
	if err != nil {
		return fmt.Errorf("could not move %v to %v: %v", f.Name(), cnf.Path, err)
	}
	log.Info(fmt.Sprintf("Updated my.cnf. Backup of previous version available in %v", backupPath))

	return nil
}

// ReinitConfig updates the config file as if Mysqld is initializing. At the
// moment it only randomizes ServerID because it's not safe to restore a replica
// from a backup and then give it the same ServerID as before, MySQL can then
// skip transactions in the replication stream with the same server_id.
func (mysqld *Mysqld) ReinitConfig(ctx context.Context, cnf *Mycnf) error {
	log.Info("Mysqld.ReinitConfig")

	// Execute as remote action on mysqlctld if requested.
	if socketFile != "" {
		log.Info(fmt.Sprintf("executing Mysqld.ReinitConfig() remotely via mysqlctld server: %v", socketFile))
		client, err := mysqlctlclient.New(ctx, "unix", socketFile)
		if err != nil {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Manually recover: mv <cnf.Path>.previous back or copy the temp file to cnf.Path.
  2. Check filesystem health, free space, and writability of the config directory.
  3. Eliminate concurrent processes that could delete the temp file during refresh.
  4. Re-run RefreshConfig once the filesystem issue is resolved.

Example fix

// before: my.cnf missing after failed rename
ls my.cnf -> No such file
// after
mv my.cnf.previous my.cnf   # or: mv /vt/vtdataroot/vt_0000000100/my.cnfXXXX my.cnf
Defensive patterns

Strategy: try-catch

Validate before calling

if unix.Access(path.Dir(cnf.Path), unix.W_OK) != nil {
    return fmt.Errorf("cannot complete refresh: %s not writable", path.Dir(cnf.Path))
}

Try / catch

if err := mysqld.RefreshConfig(ctx, cnf); err != nil {
    if strings.Contains(err.Error(), "could not move") {
        // config dir is now inconsistent: my.cnf renamed away, temp remains
        log.Errorf("recover: restore %s.previous or move temp file into place", cnf.Path)
    }
    return err
}

Prevention

When it happens

Trigger: Mysqld.RefreshConfig: os.Rename(f.Name(), cnf.Path) fails immediately after the backup rename succeeded — temp file removed concurrently, or filesystem/device mismatch preventing rename.

Common situations: Disk/full or read-only filesystem flip; concurrent cleanup deleting the temp file between the two renames; overlay/fuse filesystem with quirky rename semantics.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/7863f77fdb6fa0c1. Report an issue: GitHub.