vitessio/vitess · error

unable to create file: %v

Error message

unable to create file: %v

What it means

Thrown by createStateFile (restore preparation) when os2.Create fails on the restore state file at <tabletDir>/restore_state. The state file marks that a restore is in progress so a crash mid-restore can be detected; failure usually means the tablet directory is missing or the filesystem is unwritable.

Source

Thrown at go/vt/mysqlctl/backupengine.go:764

	logger.Infof("Restore: reinit config file")
	if err := mysqld.ReinitConfig(ctx, cnf); err != nil {
		return err
	}
	return nil
}

// create restore state file
func createStateFile(cnf *Mycnf) error {
	// if we start writing content to this file:
	// change RD_ONLY to RDWR
	// 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

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Ensure the tablet directory exists and is writable by the process user (mkdir/chown/chmod as needed).
  2. Read the wrapped OS error for the concrete cause (ENOENT, EACCES, EROFS, ENOSPC) and fix that specific condition.
  3. Check disk space on the volume holding the tablet dir.
  4. Verify the tablet_dir path configuration points at the intended location.

Example fix

// before: dir missing -> "unable to create file: open /vt/vtdataroot/vt_0000000100/restore_state: no such file or directory"
mkdir -p /vt/vtdataroot/vt_0000000100 && chown vitess:vitess /vt/vtdataroot/vt_0000000100
// after: restore proceeds
Defensive patterns

Strategy: validation

Validate before calling

dir := cnf.TabletDir()
if st, err := os.Stat(dir); err != nil || !st.IsDir() {
    return fmt.Errorf("tablet dir %s missing or not a directory", dir)
}
probe := filepath.Join(dir, ".write_probe")
if err := os.WriteFile(probe, nil, 0o644); err != nil {
    return fmt.Errorf("tablet dir not writable: %w", err)
}
os.Remove(probe)

Try / catch

if err := restore(); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && (errors.Is(pe.Err, fs.ErrPermission) || errors.Is(pe.Err, fs.ErrNotExist)) {
        // fix tablet dir permissions/existence, then retry restore
    }
    return err
}

Prevention

When it happens

Trigger: Restore flow calls createStateFile; the OS returns an error creating the file — tablet dir does not exist, wrong permissions/ownership, read-only filesystem, or disk full.

Common situations: Tablet directory deleted or never initialized before restore; mounted restore volume is read-only; running mysqlctl/vttablet as a user lacking write access to the tablet dir; ENOSPC on a full disk.

Related errors


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