wavetermdev/waveterm · error
failed to create SSH session: %w
Error message
failed to create SSH session: %w
What it means
MakeSSHCmdClient calls client.NewSession() on an established golang.org/x/crypto/ssh connection to open a channel for running a command. If the underlying SSH connection cannot open a new session channel (connection dropped, closed, or refused by the server), the error is wrapped as 'failed to create SSH session'. This happens before any command is built or started.
Source
Thrown at pkg/genconn/ssh-impl.go:48
type SSHProcessController struct {
client *ssh.Client
session *ssh.Session
lock *sync.Mutex
once *sync.Once
stdinPiped bool
stdoutPiped bool
stderrPiped bool
waitErr error
started bool
cmdSpec CommandSpec
}
// MakeSSHCmdClient creates a new instance of SSHCmdClient
func MakeSSHCmdClient(client *ssh.Client, cmdSpec CommandSpec) (*SSHProcessController, error) {
log.Printf("SSH-NEWSESSION (cmdclient)\n")
session, err := client.NewSession()
if err != nil {
return nil, fmt.Errorf("failed to create SSH session: %w", err)
}
return &SSHProcessController{
client: client,
lock: &sync.Mutex{},
once: &sync.Once{},
cmdSpec: cmdSpec,
session: session,
}, nil
}
// Start begins execution of the command
func (s *SSHProcessController) Start() error {
s.lock.Lock()
defer s.lock.Unlock()
if s.started {
return fmt.Errorf("command already started")
}View on GitHub (pinned to a4447c1563)
Solutions
- Check/verify the SSH connection is still alive (e.g. client.SendRequest keepalive) before creating the session; if dead, reconnect and rebuild the *ssh.Client.
- Retry the operation with a fresh connection — transient network drops are the most common cause.
- Raise MaxSessions on the remote sshd_config if many concurrent sessions are needed.
- Check server logs (auth.log/sshd -d) to confirm whether the server is rejecting channels.
Example fix
// before
ctrl, err := genconn.MakeSSHCmdClient(client, cmdSpec)
if err != nil { return err }
// after
if _, err := client.SendRequest("keepalive@openssh.com", true, nil); err != nil {
client, err = reconnectSSH(cfg) // rebuild dead connection
if err != nil { return err }
}
ctrl, err := genconn.MakeSSHCmdClient(client, cmdSpec)
if err != nil { return err } Defensive patterns
Strategy: retry
Validate before calling
func sshAlive(client *ssh.Client) bool {
_, _, err := client.SendRequest("keepalive@openssh.com", true, nil)
return err == nil
}
if !sshAlive(client) { client = mustReconnect() } Try / catch
ctrl, err := genconn.MakeSSHCmdClient(client, cmdSpec)
if err != nil {
log.Printf("ssh session open failed: %v; reconnecting", err)
client = reconnectSSH(cfg)
ctrl, err = genconn.MakeSSHCmdClient(client, cmdSpec)
if err != nil { return fmt.Errorf("ssh session unavailable: %w", err) }
} Prevention
- Send SSH keepalive requests (SendRequest keepalive@openssh.com) to detect dead connections early.
- Reconnect and rebuild the *ssh.Client on any session-creation failure instead of retrying on the stale client.
- Cap concurrent sessions per connection below sshd's MaxSessions (default 10).
- Monitor connection lifetime and proactively reconnect before server idle timeouts.
When it happens
Trigger: Calling MakeSSHCmdClient (directly or via SSHShellClient.MakeProcessController, used by MakeProcessController and CpWshToRemote) when the *ssh.Client's underlying connection has been closed/reset, the server rejects the session channel (MaxSessions reached), or the connection was never fully established.
Common situations: Remote host restarted or network dropped mid-connection; SSH server's MaxSessions limit hit (default 10); connection idle-timeouted by firewall/server (ClientAliveInterval); trying to reuse a client after a previous command's connection was torn down; server's sshd configured to disallow exec sessions (allowtcpforwarding/no-exec chroot).
Related errors
- ssh connection %s not connected, cannot start shellproc
- failed to start command: %w
- connection %q is not connected
- unable to request connection domain socket: %v
- cannot call ${methodName}: no web endpoint
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/b7774c3b9069575b.
Report an issue: GitHub.