kubernetes/kops · error

error writing script to SSH target: %w

Error message

error writing script to SSH target: %w

What it means

runScript writes the shell script to scriptPath on the remote host using a vfs SSH path writer. If p.WriteFile fails — session I/O error, permission denied (root-owned dir), or disk full — this error wraps it; the deferred cleanup removes the temp dir either way.

Source

Thrown at pkg/commands/toolbox_enroll.go:370

		b := make([]byte, 32)
		if _, err := cryptorand.Read(b); err != nil {
			return nil, fmt.Errorf("error getting random data: %w", err)
		}
		tempDir = path.Join("/tmp", hex.EncodeToString(b))
	}

	scriptPath := path.Join(tempDir, "script.sh")

	p := vfs.NewSSHPath(s.sshClient, s.hostname, scriptPath, s.sudo)

	defer func() {
		if _, err := s.runCommand(ctx, "rm -rf "+tempDir, ExecOptions{Echo: false}); err != nil {
			klog.Warningf("error cleaning up temp directory %q: %v", tempDir, err)
		}
	}()

	if err := p.WriteFile(ctx, bytes.NewReader([]byte(script)), nil); err != nil {
		return nil, fmt.Errorf("error writing script to SSH target: %w", err)
	}

	scriptCommand := "/bin/bash " + scriptPath
	return s.runCommand(ctx, scriptCommand, options)
}

// CommandOutput holds the results of running a command.
type CommandOutput struct {
	Stdout bytes.Buffer
	Stderr bytes.Buffer
}

// ExecOptions holds options for running a command remotely.
type ExecOptions struct {
	Echo bool
}

func (s *SSHHost) runCommand(ctx context.Context, command string, options ExecOptions) (*CommandOutput, error) {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Read the wrapped error: 'permission denied' → ensure passwordless sudo for the SSH user (visudo)
  2. Check remote /tmp: df -h /tmp and mount | grep /tmp (watch for noexec/nosuid restrictions)
  3. Verify network stability and retry enroll
  4. Manually test the equivalent: ssh <user>@<host> 'mkdir -p /tmp/test && echo ok > /tmp/test/f'

Example fix

// before
$ kops toolbox enroll ...
Error: error writing script to SSH target: mkdir /tmp/abc...: permission denied
// after
$ ssh admin@node 'sudo visudo'  # add: admin ALL=(ALL) NOPASSWD:ALL
$ df -h /tmp                    # ensure space, and /tmp not mounted noexec
$ kops toolbox enroll ...
Defensive patterns

Strategy: validation

Validate before calling

if err := exec.Command("ssh", user+"@"+host,
    "test -w /tmp && [ $(df -k --output=avail /tmp | tail -1) -gt 10240 ]").Run(); err != nil {
    return fmt.Errorf("remote /tmp not writable or <10MB free")
}

Type guard

func remoteTmpWritable(ctx context.Context, h *SSHHost) bool {
    _, err := h.runCommand(ctx, "test -w /tmp", ExecOptions{Echo: false})
    return err == nil
}

Try / catch

_, err := sshTarget.runScript(ctx, script, ExecOptions{Echo: true})
if err != nil {
    if strings.Contains(err.Error(), "error writing script to SSH target") {
        return fmt.Errorf("check remote /tmp permissions and free space: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: p.WriteFile(ctx, bytes.NewReader([]byte(script)), nil) fails: SSH session dropped mid-write, /tmp not writable, noexec/no-space /tmp, or sudo wrapping failing so the write cannot create directories under /tmp.

Common situations: Remote /tmp mounted noexec or full; enroll run against a host whose SSH user lacks sudo rights to create the temp dir; long-running script staging interrupted by network flaps.

Related errors


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