kubernetes/kops · error
renaming sftp file %q -> %q (with posix rename): %w
Error message
renaming sftp file %q -> %q (with posix rename): %w
What it means
This is the final atomic swap: sftpClient.Rename(tempfile, p.path) moves the staged temp file onto the destination. If the SFTP server's posix-rename extension is unavailable or the rename fails (e.g. destination re-created between Remove and Rename, connection dropped), this error wraps the cause.
Source
Thrown at util/pkg/vfs/sshfs.go:244
if err != nil {
return fmt.Errorf("error during chmod of %q: %w", tempfile, err)
}
}
}
// posix rename will replace the destination (normal sftp rename does not)
usePosixRename := true
if usePosixRename {
// posix rename fails if destination exists, try to delete just in case
if err := sftpClient.Remove(p.path); err != nil {
if os.IsNotExist(err) {
// expected when file does not exist already
} else {
return fmt.Errorf("removing destination sftp file %q before rename: %w", p.path, err)
}
}
if err := sftpClient.Rename(tempfile, p.path); err != nil {
return fmt.Errorf("renaming sftp file %q -> %q (with posix rename): %w", tempfile, p.path, err)
}
deleteTempFile = false
} else {
var session *ssh.Session
session, err = p.client.NewSession()
if err != nil {
return fmt.Errorf("creating session for rename: %w", err)
}
defer session.Close()
cmd := "mv " + tempfile + " " + p.path
if p.sudo {
cmd = "sudo " + cmd
}
if err := session.Run(cmd); err != nil {
return fmt.Errorf("renaming file %q -> %q (with %q): %w", tempfile, p.path, cmd, err)
}
deleteTempFile = falseView on GitHub (pinned to 4c8573c808)
Solutions
- Retry the whole WriteFile — the temp file is cleaned up and a fresh attempt uses a new temp name.
- Check for concurrent writers to the same path and serialize the operation (kOps already locks per-process via createFileLockSSH).
- Ensure the SFTP server supports the posix-rename extension (OpenSSH >= 5.7-ish; upgrade sshd if ancient).
- Inspect the wrapped error: if it is 'failure' with existing destination, look for what recreates the destination between Remove and Rename.
Example fix
// before: two tools writing same manifest concurrently kubelet-static (watcher) recreates manifest <-> kops WriteFile rename fails // after: pause/coordinate the other writer, then re-run kops update cluster
Defensive patterns
Strategy: retry
Validate before calling
// ensure no concurrent writers and destination dir is stable
out := sshRun(host, fmt.Sprintf("fuser %s 2>/dev/null; test -d %s && echo stable", dest, path.Dir(dest))) Try / catch
err := path.WriteFile(ctx, data, acl)
if err != nil && strings.Contains(err.Error(), "renaming sftp file") {
time.Sleep(2 * time.Second)
return path.WriteFile(ctx, data, acl) // fresh temp name each attempt
} Prevention
- Serialize writes to the same remote path across processes/tools.
- Use a modern sshd supporting the posix-rename extension.
- Retry on failure — the library guarantees temp-file cleanup so retries are safe.
When it happens
Trigger: sftpClient.Rename fails after the destination was removed: another process recreated the destination file (posix rename fails on existing destination), SFTP server lacks the posix-rename@openssh.com extension behavior, or the SSH connection dropped.
Common situations: Concurrent writers (e.g. kubelet plus kOps) touching the same manifest file; old SSH/SFTP servers without the extension; symlink at destination recreated by a watcher between Remove and Rename.
Related errors
- error creating sftp client: %w
- error creating sftp client (in new-session): %w
- error creating sftp client (at stdin pipe): %w
- not a directory: %q
- error creating directory %q over sftp: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/97d0880f65481ad5.
Report an issue: GitHub.