{"record":{"id":"158c5018e5769b55","repo":"kubernetes/kops","slug":"failed-to-start-ssh-session-w","errorCode":null,"errorMessage":"failed to start SSH session: %w","messagePattern":"failed to start SSH session: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/toolbox_enroll.go","lineNumber":391,"sourceCode":"\tscriptCommand := \"/bin/bash \" + scriptPath\n\treturn s.runCommand(ctx, scriptCommand, options)\n}\n\n// CommandOutput holds the results of running a command.\ntype CommandOutput struct {\n\tStdout bytes.Buffer\n\tStderr bytes.Buffer\n}\n\n// ExecOptions holds options for running a command remotely.\ntype ExecOptions struct {\n\tEcho bool\n}\n\nfunc (s *SSHHost) runCommand(ctx context.Context, command string, options ExecOptions) (*CommandOutput, error) {\n\tsession, err := s.sshClient.NewSession()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to start SSH session: %w\", err)\n\t}\n\tdefer session.Close()\n\n\toutput := &CommandOutput{}\n\n\tsession.Stdout = &output.Stdout\n\tsession.Stderr = &output.Stderr\n\n\tif options.Echo {\n\t\t// We send both to stderr, so we don't \"corrupt\" stdout\n\t\tsession.Stdout = io.MultiWriter(os.Stderr, session.Stdout)\n\t\tsession.Stderr = io.MultiWriter(os.Stderr, session.Stderr)\n\t}\n\tif s.sudo {\n\t\tcommand = \"sudo \" + command\n\t}\n\tif err := session.Run(command); err != nil {\n\t\treturn output, fmt.Errorf(\"error running command %q: %w\", command, err)","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/commands/toolbox_enroll.go#L373-L409","documentation":"This error wraps a failure to create a new SSH session on an already-established SSH client connection (sshClient.NewSession()). kOps' toolbox enroll uses this to run remote commands (runScript, getHostname) on a target host. It indicates the SSH connection exists but cannot open a channel/session, typically because the connection dropped or the server refused the channel.","triggerScenarios":"Calling SSHHost.runCommand (directly or via runScript/getHostname) when the underlying TCP connection to the host has been reset/timed out, the SSH server has hit MaxSessions, or the server closed the connection.","commonSituations":"Long-running enroll workflows where an idle SSH connection was reaped by a firewall/NAT; SSH server MaxSessions exhausted; host rebooted mid-enroll; network flakiness to the node.","solutions":["Verify the host is reachable and SSH daemon is running (ssh user@host 'echo ok')","Re-establish the SSH connection and retry the command (transient failures are common)","Check sshd MaxSessions/MaxStartups on the target and raise if enrolling many hosts concurrently","Check for NAT/firewall idle timeouts and enable SSH keepalives"],"exampleFix":"// before\noutput, err := host.runCommand(ctx, \"hostname\", opts) // fails once connection dropped\n// after\nif err != nil && isSSHSessionError(err) {\n    host.reconnect(ctx) // re-dial sshClient\n    output, err = host.runCommand(ctx, \"hostname\", opts)\n}","handlingStrategy":"retry","validationCode":"// before enrolling\nout, err := exec.Command(\"ssh\", \"-o\", \"BatchMode=yes\", \"-o\", \"ConnectTimeout=5\", user+\"@\"+host, \"echo ok\").CombinedOutput()\nif err != nil { return fmt.Errorf(\"SSH unreachable for %s: %v: %s\", host, err, out) }","typeGuard":"func isSSHSessionError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"failed to start SSH session\")\n}","tryCatchPattern":"out, err := host.runCommand(ctx, cmd, opts)\nif isSSHSessionError(err) {\n    host.reconnect(ctx)\n    out, err = host.runCommand(ctx, cmd, opts)\n}","preventionTips":["Enable SSH keepalives to survive NAT/firewall idle timeouts","Retry transient session failures with backoff","Avoid many concurrent sessions to one host (MaxSessions)","Monitor host reachability before starting enroll"],"tags":["ssh","network"],"backgroundTag":"ssh-session-open-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"}