{"record":{"id":"f88ed17a464622a0","repo":"wavetermdev/waveterm","slug":"failed-to-start-command-w","errorCode":null,"errorMessage":"failed to start command: %w","messagePattern":"failed to start command: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/genconn/ssh-impl.go","lineNumber":78,"sourceCode":"func (s *SSHProcessController) Start() error {\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n\n\tif s.started {\n\t\treturn fmt.Errorf(\"command already started\")\n\t}\n\n\tfullCmd, err := BuildShellCommand(s.cmdSpec)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to build shell command: %w\", err)\n\t}\n\t// if stdout/stderr weren't piped, then session.stdout/stderr will be nil\n\t// and the library guarantees that the outputs will be attached to io.Discard\n\t// if stdin hasn't been piped, then session.stdin will be nil\n\t// and the libary guarantees that it will be attached to an empty bytes.Buffer, which will produce an immediate EOF\n\t// tl;dr we don't need to worry about hanging beause of long input or explicitly closing stdin\n\tif err := s.session.Start(fullCmd); err != nil {\n\t\treturn fmt.Errorf(\"failed to start command: %w\", err)\n\t}\n\ts.started = true\n\treturn nil\n}\n\n// Wait waits for the command to complete\nfunc (s *SSHProcessController) Wait() error {\n\ts.once.Do(func() {\n\t\ts.waitErr = s.session.Wait()\n\t})\n\treturn s.waitErr\n}\n\n// Kill terminates the command\nfunc (s *SSHProcessController) Kill() {\n\ts.lock.Lock()\n\tdefer s.lock.Unlock()\n","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/genconn/ssh-impl.go#L60-L96","documentation":"After building the full command string, Start() calls session.Start(fullCmd) on the golang.org/x/crypto/ssh session. If the remote side refuses to begin execution of the command (channel/request error at the SSH protocol level), the error is wrapped as 'failed to start command'. The session channel exists but the exec request failed.","triggerScenarios":"Calling Start() when the underlying SSH connection broke between session creation and Start, the remote sshd rejects the exec request, or the requested executable/shell cannot be invoked on the remote side.","commonSituations":"Network drop right after session creation; remote shell path in CommandSpec does not exist on the host (e.g. zsh not installed); sshd forced-command restrictions rejecting arbitrary exec; server overloaded/out of PTYs.","solutions":["Check the wrapped error: 'connection lost' style errors mean reconnect and retry; request-failed means inspect remote sshd restrictions.","Verify the shell/executable named in the CommandSpec exists on the remote host (which bash).","Test the same command manually over plain ssh to rule out forced-command/Match restrictions.","Add keepalives to detect dead connections before Start."],"exampleFix":"// before\nerr := ctrl.Start() // opaque ssh error, controller unusable\n// after\nif err := ctrl.Start(); err != nil {\n    if strings.Contains(err.Error(), \"connection lost\") || strings.Contains(err.Error(), \"EOF\") {\n        client = reconnectSSH(cfg)\n        ctrl, err = genconn.MakeSSHCmdClient(client, spec)\n        if err == nil { err = ctrl.Start() }\n    }\n    if err != nil { return err }\n}","handlingStrategy":"retry","validationCode":"func remoteHasShell(client *ssh.Client, shell string) bool {\n    out, err := client.NewSession(); if err != nil { return false }\n    defer out.Close()\n    err = out.Run(\"command -v \" + shell)\n    return err == nil\n}","typeGuard":null,"tryCatchPattern":"if err := ctrl.Start(); err != nil {\n    if isConnError(err) { // EOF, \"connection lost\", \"broken pipe\"\n        client = reconnectSSH(cfg)\n        ctrl, _ = genconn.MakeSSHCmdClient(client, spec)\n        return ctrl.Start()\n    }\n    return fmt.Errorf(\"remote refused exec (check sshd restrictions / shell path): %w\", err)\n}","preventionTips":["Enable SSH keepalives so dead connections fail fast and predictably.","Verify the shell/executable named in the spec exists on target hosts (pinned images/AMI baselines).","Keep sshd Match/ForceCommand restrictions in sync with what your app executes.","Retry Start on a fresh connection for transient (EOF/reset) wrapped errors."],"tags":["ssh","exec","network"],"backgroundTag":"ssh-exec-request-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}