{"record":{"id":"a32f8c305d0ae32f","repo":"kubernetes/kops","slug":"error-creating-ssh-session-v","errorCode":null,"errorMessage":"error creating ssh session: %v","messagePattern":"error creating ssh session: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/dump/dumper.go","lineNumber":601,"sourceCode":"// sshClientImplementation is the default implementation of sshClient, binding to a *ssh.Client\ntype sshClientImplementation struct {\n\tclient    *ssh.Client\n\tforwardTo string\n}\n\nvar _ sshClient = &sshClientImplementation{}\n\n// ExecPiped implements sshClientImplementation::ExecPiped\nfunc (s *sshClientImplementation) ExecPiped(ctx context.Context, cmd string, stdout io.Writer, stderr io.Writer) error {\n\tif ctx.Err() != nil {\n\t\treturn ctx.Err()\n\t}\n\n\tfinished := make(chan error)\n\tgo func() {\n\t\tsession, err := s.client.NewSession()\n\t\tif err != nil {\n\t\t\tfinished <- fmt.Errorf(\"error creating ssh session: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tdefer session.Close()\n\n\t\tsession.Stdout = stdout\n\t\tsession.Stderr = stderr\n\n\t\tif s.forwardTo != \"\" {\n\t\t\tcmd = fmt.Sprintf(\"ssh -o 'StrictHostKeyChecking no' %s %s\", quoteShell(s.forwardTo), quoteShell(cmd))\n\t\t}\n\n\t\tklog.V(2).Infof(\"running SSH command: %v\", cmd)\n\n\t\tfinished <- session.Run(cmd)\n\t}()\n\n\tselect {\n\tcase <-ctx.Done():","sourceCodeStart":583,"sourceCodeEnd":619,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/dump/dumper.go#L583-L619","documentation":"Produced inside sshClientImplementation.ExecPiped (pkg/dump/dumper.go:601) when s.client.NewSession() fails on the established *ssh.Client connection. The goroutine sends this error on the finished channel; ExecPiped returns it unless the context expires first. It means the SSH transport is still up (or believed to be) but no new channel could be opened — typically a client/server session or resource limit.","triggerScenarios":"s.client.NewSession() returns an error: sshd MaxSessions (default 10) exhausted on the target node, the underlying TCP connection was reset/closed by the server or a middlebox, the server refused the channel ('session open failed'), or the client connection was already closed.","commonSituations":"Dumping many nodes/services in parallel while other tooling holds SSH channels to the same node (MaxSessions hit); NAT/firewall idle timeouts killing the connection between Dial and the command run; bastion-forwarded connections dropping; long dumps where the connection goes stale mid-run.","solutions":["Raise sshd MaxSessions on the node (drop-in in /etc/ssh/sshd_config.d) if many channels are opened concurrently, then restart sshd.","Retry the command: reconnect via Dial instead of reusing a possibly-stale client, since NewSession failure often means the transport is dead.","Check for idle-connection timeouts (NAT, security appliance, sshd ClientAliveInterval) and enable keepalives on the SSH dialer.","Verify the connection wasn't closed early by the caller (n.Close() racing with in-flight dumps).","Inspect the wrapped error text — 'connection reset by peer' vs 'session open failed' distinguishes network drops from server-side channel limits."],"exampleFix":"// before\nsession, err := s.client.NewSession()\nif err != nil {\n    finished <- fmt.Errorf(\"error creating ssh session: %v\", err)\n    return\n}\n// after (caller-side: re-dial on session failure)\nsession, err := s.client.NewSession()\nif err != nil {\n    finished <- fmt.Errorf(\"error creating ssh session: %w\", err)\n    return\n}","handlingStrategy":"retry","validationCode":"// verify the transport is alive before opening a session\nif s.client.Conn() == nil || s.client.Conn().Closed() {\n    return fmt.Errorf(\"ssh transport already closed; redial required\")\n}","typeGuard":null,"tryCatchPattern":"session, err := s.client.NewSession()\nif err != nil {\n    // retry once after redial\n    if client2, dialErr := factory.Dial(ctx, host, useBastion); dialErr == nil {\n        if s2, e2 := client2.NewSession(); e2 == nil {\n            session = s2\n            err = nil\n        }\n    }\n}\nif err != nil {\n    finished <- fmt.Errorf(\"error creating ssh session: %w\", err)\n    return\n}","preventionTips":["Raise sshd MaxSessions on nodes if many channels are opened per connection.","Enable TCP keepalives on the SSH dialer to survive NAT/firewall idle timeouts.","Redial a fresh connection instead of reusing a client after any NewSession failure.","Avoid holding the ssh.Client open across long idle periods."],"tags":["ssh","session","connection-limit","go"],"backgroundTag":"ssh-max-sessions-exceeded","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"}