{"record":{"id":"4d1089c2573f189d","repo":"kubernetes/kops","slug":"writing-file-q-over-ssh-w","errorCode":null,"errorMessage":"writing file %q over SSH: %w","messagePattern":"writing file %q over SSH: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/toolbox_enroll.go","lineNumber":241,"sourceCode":"\n\tkubeClient, err := client.New(restConfigNoProto, client.Options{\n\t\tScheme: scheme,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"building kubernetes client: %w\", err)\n\t}\n\n\t// We can't create the host resource in the API server for control-plane nodes,\n\t// because the API server (likely) isn't running yet.\n\tif !ig.IsControlPlane() {\n\t\tif err := kubeClient.Create(ctx, hostData); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create host %s/%s: %w\", hostData.Namespace, hostData.Name, err)\n\t\t}\n\t}\n\n\tfor k, v := range bootstrapData.NodeupScriptAdditionalFiles {\n\t\tif err := sshTarget.writeFile(ctx, k, bytes.NewReader(v)); err != nil {\n\t\t\treturn fmt.Errorf(\"writing file %q over SSH: %w\", k, err)\n\t\t}\n\t}\n\n\tif len(bootstrapData.NodeupScript) != 0 {\n\t\tif _, err := sshTarget.runScript(ctx, string(bootstrapData.NodeupScript), ExecOptions{Echo: true}); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nconst scriptCreateKey = `\n#!/bin/bash\nset -o errexit\nset -o nounset\nset -o pipefail\n\nset -x","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/commands/toolbox_enroll.go#L223-L259","documentation":"While staging additional nodeup files listed in bootstrapData.NodeupScriptAdditionalFiles, writeFile copies each file's contents over the SSH connection to the target host. This error wraps whatever failure the SSH write encountered (I/O error on the SSH session, permission denied on the destination path, disk full).","triggerScenarios":"sshTarget.writeFile(ctx, k, bytes.NewReader(v)) fails for a specific file k: SSH session dropped, remote path not writable by the SSH user (even with sudo wrapper failing), or remote filesystem errors.","commonSituations":"Enrolling a node where /etc/kubernetes or the script's target dirs are root-owned and sudo is not correctly configured (no passwordless sudo for the user), full /var or /tmp partition, or flaky network killing the SSH session mid-transfer.","solutions":["Read the wrapped error: if permission denied, ensure the SSH user has passwordless sudo (visudo: user ALL=(ALL) NOPASSWD:ALL)","Check remote disk space: df -h on the target host","Verify network stability to the host and retry the enroll command","Confirm the destination file path is correct and not immutable (chattr +i)"],"exampleFix":"// before\nif err := sshTarget.writeFile(ctx, k, bytes.NewReader(v)); err != nil {\n    return fmt.Errorf(\"writing file %q over SSH: %w\", k, err)\n}\n// after\nif err := sshTarget.writeFile(ctx, k, bytes.NewReader(v)); err != nil {\n    if strings.Contains(err.Error(), \"permission denied\") {\n        return fmt.Errorf(\"writing file %q over SSH: permission denied; ensure SSH user has passwordless sudo: %w\", k, err)\n    }\n    return fmt.Errorf(\"writing file %q over SSH: %w\", k, err)\n}","handlingStrategy":"validation","validationCode":"ssh <user>@<host> 'test -w /etc/kubernetes/kops && df -h /var | awk \"NR==2{exit ($4+0>5)?0:1}\"' \\\n  || echo \"target not writable or low disk\"","typeGuard":"func sshWritable(ctx context.Context, h *SSHHost, dir string) bool {\n    _, err := h.runCommand(ctx, \"test -w \"+dir, ExecOptions{Echo: false})\n    return err == nil\n}","tryCatchPattern":"if err := sshTarget.writeFile(ctx, k, bytes.NewReader(v)); err != nil {\n    return fmt.Errorf(\"writing file %q over SSH: %w\", k, err)\n}","preventionTips":["Grant passwordless sudo to the enroll SSH user","Check remote disk space before large file staging","Prefer stable networks / retries for long SSH transfers"],"tags":["ssh","file-transfer"],"backgroundTag":"ssh-file-write-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}