{"record":{"id":"97d0880f65481ad5","repo":"kubernetes/kops","slug":"renaming-sftp-file-q-q-with-posix-rename","errorCode":null,"errorMessage":"renaming sftp file %q -> %q (with posix rename): %w","messagePattern":"renaming sftp file %q -> %q \\(with posix rename\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/vfs/sshfs.go","lineNumber":244,"sourceCode":"\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error during chmod of %q: %w\", tempfile, err)\n\t\t\t}\n\t\t}\n\t}\n\n\t// posix rename will replace the destination (normal sftp rename does not)\n\tusePosixRename := true\n\tif usePosixRename {\n\t\t// posix rename fails if destination exists, try to delete just in case\n\t\tif err := sftpClient.Remove(p.path); err != nil {\n\t\t\tif os.IsNotExist(err) {\n\t\t\t\t// expected when file does not exist already\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"removing destination sftp file %q before rename: %w\", p.path, err)\n\t\t\t}\n\t\t}\n\t\tif err := sftpClient.Rename(tempfile, p.path); err != nil {\n\t\t\treturn fmt.Errorf(\"renaming sftp file %q -> %q (with posix rename): %w\", tempfile, p.path, err)\n\t\t}\n\t\tdeleteTempFile = false\n\t} else {\n\t\tvar session *ssh.Session\n\t\tsession, err = p.client.NewSession()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"creating session for rename: %w\", err)\n\t\t}\n\t\tdefer session.Close()\n\n\t\tcmd := \"mv \" + tempfile + \" \" + p.path\n\t\tif p.sudo {\n\t\t\tcmd = \"sudo \" + cmd\n\t\t}\n\t\tif err := session.Run(cmd); err != nil {\n\t\t\treturn fmt.Errorf(\"renaming file %q -> %q (with %q): %w\", tempfile, p.path, cmd, err)\n\t\t}\n\t\tdeleteTempFile = false","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/vfs/sshfs.go#L226-L262","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: two tools writing same manifest concurrently\nkubelet-static (watcher) recreates manifest <-> kops WriteFile rename fails\n// after: pause/coordinate the other writer, then re-run kops update cluster","handlingStrategy":"retry","validationCode":"// ensure no concurrent writers and destination dir is stable\nout := sshRun(host, fmt.Sprintf(\"fuser %s 2>/dev/null; test -d %s && echo stable\", dest, path.Dir(dest)))","typeGuard":null,"tryCatchPattern":"err := path.WriteFile(ctx, data, acl)\nif err != nil && strings.Contains(err.Error(), \"renaming sftp file\") {\n    time.Sleep(2 * time.Second)\n    return path.WriteFile(ctx, data, acl) // fresh temp name each attempt\n}","preventionTips":["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."],"tags":["ssh","sftp","rename","concurrency"],"backgroundTag":"sftp-rename-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}