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
- Manually recover: mv <cnf.Path>.previous back or copy the temp file to cnf.Path.
- Check filesystem health, free space, and writability of the config directory.
- Eliminate concurrent processes that could delete the temp file during refresh.
- 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
- Monitor free space and mount state on tablet hosts
- Prevent concurrent cleaners from touching the config dir
- Have a runbook to restore my.cnf from my.cnf.previous
- Prefer overlay-free (ext4/xfs) filesystems for VTDATAROOT
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
- could not back up existing %v: %v
- RENAME clause found
- AttemptRecoveryRegistration: Active recovery (id:%v) in the
- failed to create file-based writer for --opentsdb-uri %s: %v
- missing file on disk: %s (%w)
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/7863f77fdb6fa0c1.
Report an issue: GitHub.