{"record":{"id":"2259c1dfa4cb3287","repo":"kubernetes/kops","slug":"writing-to-sftp-temp-file-w","errorCode":null,"errorMessage":"writing to sftp temp file: %w","messagePattern":"writing to sftp temp file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/vfs/sshfs.go","lineNumber":212,"sourceCode":"\t\tif shouldClose {\n\t\t\t// Something went wrong; try to close the temp file\n\t\t\tif err := f.Close(); err != nil {\n\t\t\t\tklog.Warningf(\"unable to close temp file %q: %v\", tempfile, err)\n\t\t\t}\n\t\t}\n\t}()\n\n\tdeleteTempFile := true\n\tdefer func() {\n\t\tif deleteTempFile {\n\t\t\t// Something went wrong; try to remove the temp file\n\t\t\tif err := sftpClient.Remove(tempfile); err != nil {\n\t\t\t\tklog.Warningf(\"unable to remove temp file %q: %v\", tempfile, err)\n\t\t\t}\n\t\t}\n\t}()\n\tif _, err := io.Copy(f, data); err != nil {\n\t\treturn fmt.Errorf(\"writing to sftp temp file: %w\", err)\n\t}\n\n\tshouldClose = false\n\tif err := f.Close(); err != nil {\n\t\treturn err\n\t}\n\n\tif acl != nil {\n\t\tsshACL, ok := acl.(*SSHAcl)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected acl type %T\", acl)\n\t\t} else {\n\t\t\terr = sftpClient.Chmod(tempfile, sshACL.Mode)\n\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}","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/vfs/sshfs.go#L194-L230","documentation":"WriteFile streams the caller's io.ReadSeeker into the SFTP temp file with io.Copy. If the copy fails mid-transfer (network interruption, SFTP server-side write failure, disk full), the error is wrapped with this message. The deferred cleanup then removes the orphaned temp file.","triggerScenarios":"io.Copy(f, data) fails during WriteFile: SSH connection dropped mid-write, remote disk filled during transfer, SFTP server returned an I/O error, or the source reader itself errored.","commonSituations":"Flaky network or SSH keepalive timeouts when pushing large cluster state files to a node; disk-full on remote node during large writes; firewall/NAT dropping long-lived SSH connections.","solutions":["Retry the operation — the temp file is cleaned up automatically so a retry is safe.","Check network stability to the SSH host (ping, ssh keepalives: ServerAliveInterval in ~/.ssh/config).","Check remote disk space (`df -h`) if the wrapped error indicates write failure/ENOSPC.","For large files, investigate SFTP subsystem limits or MTU/VPN issues on the path."],"exampleFix":"// before: flaky VPN drops connection during large write\nkops update cluster ... // fails: writing to sftp temp file: EOF\n// after: enable ssh keepalives in ~/.ssh/config\nHost mynode\n  ServerAliveInterval 30\n  ServerAliveCountMax 6","handlingStrategy":"retry","validationCode":"// probe connection stability before large writes\nconn, err := net.DialTimeout(\"tcp\", host+\":22\", 5*time.Second)\nif err != nil { return fmt.Errorf(\"host unreachable: %w\", err) }\nconn.Close()","typeGuard":null,"tryCatchPattern":"err := path.WriteFile(ctx, data, acl)\nif err != nil && strings.Contains(err.Error(), \"writing to sftp temp file\") {\n    if netErr, ok := errors.Unwrap(err).(net.Error); ok && netErr.Timeout() {\n        time.Sleep(backoff)\n        return path.WriteFile(ctx, data, acl) // temp file was cleaned up; safe\n    }\n    return err\n}","preventionTips":["Configure SSH keepalives (ServerAliveInterval) for long transfers.","Keep transfers small or chunk large state files.","Alert on remote disk-full conditions (ENOSPC) before they break writes."],"tags":["ssh","sftp","network","io"],"backgroundTag":"ssh-connection-dropped","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"}