kubernetes/kops · error
error during file write of %q: rename failed: %v
Error message
error during file write of %q: rename failed: %v
What it means
WriteFile stages data in a temp file and then atomically moves it into place with os.Rename(tempfile, p.location). This error is thrown when the rename fails — typically the temp file and target are on different filesystems/mounts, or the target directory's permissions changed. At this point the data was written and closed, but the final file was not updated.
Source
Thrown at util/pkg/vfs/fs.go:78
f, err := os.CreateTemp(dir, "tmp")
if err != nil {
return fmt.Errorf("error creating temp file in %q: %v", dir, err)
}
// Note from here on in we have to close f and delete or rename the temp file
tempfile := f.Name()
_, err = io.Copy(f, data)
if closeErr := f.Close(); err == nil {
err = closeErr
}
if err == nil {
err = os.Rename(tempfile, p.location)
if err != nil {
err = fmt.Errorf("error during file write of %q: rename failed: %v", p.location, err)
}
}
if err == nil {
return nil
}
// Something went wrong; try to remove the temp file
if removeErr := os.Remove(tempfile); removeErr != nil {
klog.Warningf("unable to remove temp file %q: %v", tempfile, removeErr)
}
return err
}
// To prevent concurrent creates on the same file while maintaining atomicity of writes,
// we take a process-wide lock during the operation.
// Not a great approach, but fine for a single process (with low concurrency)View on GitHub (pinned to 4c8573c808)
Solutions
- Ensure p.location is a file path, not an existing directory, and its parent is writable.
- Verify the temp file and target reside on the same filesystem (no mount point inserted between them).
- Check directory permissions/immutable flags (lsattr) and remove the immutable bit if set.
- Re-run the write; rename is atomic and a transient mount change is the usual culprit.
Example fix
// before
FSPath{location: "/srv/state/cluster"} // cluster exists as a directory -> rename fails
// after
FSPath{location: "/srv/state/cluster/spec.yaml"} Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(target); err == nil && fi.IsDir() {
return fmt.Errorf("target %s is a directory; rename would fail", target)
}
// same-filesystem check for the staging directory
if err := sameFilesystem(filepath.Dir(target), filepath.Dir(target)); err != nil {
return err
} Try / catch
if err := p.WriteFile(ctx, data, acl); err != nil && strings.Contains(err.Error(), "rename failed") {
if errors.Is(errors.Unwrap(errors.Unwrap(err)), syscall.EXDEV) {
return fmt.Errorf("temp file and target are on different filesystems: %w", err)
}
return err
} Prevention
- Point FSPath at a file path, never an existing directory.
- Keep temp files and targets on the same mount (avoid bind-mount surprises).
- Keep parent directories writable and free of immutable flags (chattr +i).
When it happens
Trigger: Calling CreateFile/WriteFile where os.Rename fails: target directory not writable (cannot replace/create the final name), p.location is a directory, or the temp dir and target are on different mount points after a bind mount/overlay change.
Common situations: p.location pointing at an existing directory instead of a file, the parent directory becoming read-only mid-write, container volume mounts making the temp file land on a different device than the target.
Related errors
- reading file %q: %v
- error renaming extracted temp dir %s -> %s: %v
- error moving downloaded file %q to %q: %v
- error creating directories %q: %v
- error creating temp file in %q: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/517e870d33a82075.
Report an issue: GitHub.