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 = false

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Retry the whole WriteFile — the temp file is cleaned up and a fresh attempt uses a new temp name.
  2. Check for concurrent writers to the same path and serialize the operation (kOps already locks per-process via createFileLockSSH).
  3. Ensure the SFTP server supports the posix-rename extension (OpenSSH >= 5.7-ish; upgrade sshd if ancient).
  4. 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

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


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/97d0880f65481ad5. Report an issue: GitHub.