vitessio/vitess · error
could not back up existing %v: %v
Error message
could not back up existing %v: %v
What it means
RefreshConfig detected a config change and tried to back up the current my.cnf by renaming it to my.cnf.previous, but os.Rename failed. Wrapped from the OS; usually a permissions or cross-filesystem issue.
Source
Thrown at go/vt/mysqlctl/mysqld.go:1596
existing, err := os.ReadFile(cnf.Path)
if err != nil {
return fmt.Errorf("could not read existing file %v: %v", cnf.Path, err)
}
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.View on GitHub (pinned to 01a25a7d17)
Solutions
- Check that cnf.Path still exists and the containing directory is writable.
- Fix ownership of my.cnf and the directory (chown to the vitess user).
- Remove a stale my.cnf.previous if it is read-only and blocking the rename.
- Re-run RefreshConfig after resolving permissions.
Example fix
// before -r--r--r-- my.cnf (owned by root), dir not writable // after chown vitess:vitess my.cnf my.cnf.previous 2>/dev/null; chmod u+w . my.cnf
Defensive patterns
Strategy: validation
Validate before calling
dir := path.Dir(cnf.Path)
if info, err := os.Stat(dir); err != nil || !info.IsDir() {
return fmt.Errorf("dir %s not usable for rename: %w", dir, err)
}
if unix.Access(dir, unix.W_OK) != nil {
return fmt.Errorf("dir %s not writable", dir)
} Try / catch
if err := mysqld.RefreshConfig(ctx, cnf); err != nil {
if strings.Contains(err.Error(), "could not back up existing") {
log.Errorf("fix ownership/permissions on %s before refreshing: %v", cnf.Path, err)
}
return err
} Prevention
- Run refresh and tablet init as the same OS user
- Remove stale read-only my.cnf.previous files proactively
- Keep config dirs on a writable local filesystem
- Check TOCTOU: avoid external removal of my.cnf during refresh
When it happens
Trigger: Mysqld.RefreshConfig where bytes differ: os.Rename(cnf.Path, cnf.Path+".previous") fails because cnf.Path doesn't exist, is owned by another user, or the directory is not writable.
Common situations: my.cnf deleted between the read and rename (TOCTOU); running refresh as different user than tablet init; directory mounted read-only.
Related errors
- cannot stat hook %v: %v
- unable to create file: %v
- could not create temp file: %v
- could not read existing file %v: %v
- could not move %v to %v: %v
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/6bf793c153de06cb.
Report an issue: GitHub.