vitessio/vitess · error
unable to delete file: %v
Error message
unable to delete file: %v
What it means
removeStateFile deletes the restore state file from the tablet directory after a successful restore. If os.Remove fails for any reason (missing file, permissions, I/O error), the underlying error is wrapped with this message. It signals that leftover restore state could not be cleaned up, which may make the next restore think a previous one was interrupted.
Source
Thrown at go/vt/mysqlctl/backupengine.go:776
// change Create to Open
// rename func to openStateFile
// change to return a *File
fname := filepath.Join(cnf.TabletDir(), RestoreState)
fd, err := os2.Create(fname)
if err != nil {
return fmt.Errorf("unable to create file: %v", err)
}
if err = fd.Close(); err != nil {
return fmt.Errorf("unable to close file: %v", err)
}
return nil
}
// delete restore state file
func removeStateFile(cnf *Mycnf) error {
fname := filepath.Join(cnf.TabletDir(), RestoreState)
if err := os.Remove(fname); err != nil {
return fmt.Errorf("unable to delete file: %v", err)
}
return nil
}
// RestoreWasInterrupted tells us whether a previous restore
// was interrupted and we are now retrying it
func RestoreWasInterrupted(cnf *Mycnf) bool {
name := filepath.Join(cnf.TabletDir(), RestoreState)
_, err := os.Stat(name)
return err == nil
}
// GetBackupDir returns the directory where backups for the
// given keyspace/shard are (or will be) stored
func GetBackupDir(keyspace, shard string) string {
return fmt.Sprintf("%v/%v", keyspace, shard)
}
View on GitHub (pinned to 01a25a7d17)
Solutions
- Check that the tablet directory is writable by the process user (ls -ld on the tablet dir).
- Verify whether the state file exists; if it is simply missing, treat cleanup as done (skip os.Remove when os.IsNotExist).
- Inspect the wrapped %v error for the concrete errno (ENOENT vs EACCES vs EIO) and fix accordingly.
- Rerun the restore; the state file is only leftover state, not data.
Example fix
// before
if err := os.Remove(fname); err != nil {
return fmt.Errorf("unable to delete file: %v", err)
}
// after
if err := os.Remove(fname); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("unable to delete file %s: %w", fname, err)
}
return nil Defensive patterns
Strategy: validation
Validate before calling
if _, err := os.Stat(fname); err == nil {
if err := os.Remove(fname); err != nil {
return fmt.Errorf("unable to delete file %s: %w", fname, err)
}
} Try / catch
if err := removeStateFile(cnf); err != nil {
log.Warn("restore state file cleanup failed", slog.Any("error", err))
// non-fatal: next restore will see RestoreWasInterrupted and clean up
} Prevention
- Ensure the tablet directory is owned by the user running vitess processes.
- Treat ENOENT on cleanup paths as success, not failure.
- Monitor disk health; EIO on unlink usually precedes bigger filesystem problems.
When it happens
Trigger: Called during restore cleanup in mysqlctl; os.Remove fails on <TabletDir>/<RestoreState> because the file is absent, the vitess user lacks write permission on the tablet directory, or the filesystem reports an I/O error.
Common situations: Tablet directory ownership/permissions wrong after running as different user; state file already removed by concurrent cleanup; disk full or read-only mount after a crash.
Related errors
- unable to create file: %v
- unable to close file: %v
- ReadFile cannot be called on read-write backup
- AddFile cannot be called on read-only backup
- EndBackup cannot be called on read-only backup
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/1b19b71d2fd6617d.
Report an issue: GitHub.