{"record":{"id":"9131a7bf192b5b8c","repo":"wavetermdev/waveterm","slug":"failed-to-start-command-w-9131a7","errorCode":null,"errorMessage":"failed to start command: %w","messagePattern":"failed to start command: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobmanager/jobcmd.go","lineNumber":64,"sourceCode":"\t\tjobId: jobId,\n\t}\n\tif cmdDef.TermSize.Rows == 0 || cmdDef.TermSize.Cols == 0 {\n\t\tcmdDef.TermSize.Rows = 25\n\t\tcmdDef.TermSize.Cols = 80\n\t}\n\tif cmdDef.TermSize.Rows <= 0 || cmdDef.TermSize.Cols <= 0 {\n\t\treturn nil, fmt.Errorf(\"invalid term size: %v\", cmdDef.TermSize)\n\t}\n\tecmd := exec.Command(cmdDef.Cmd, cmdDef.Args...)\n\tif len(cmdDef.Env) > 0 {\n\t\tecmd.Env = make([]string, 0, len(cmdDef.Env))\n\t\tfor key, val := range cmdDef.Env {\n\t\t\tecmd.Env = append(ecmd.Env, fmt.Sprintf(\"%s=%s\", key, val))\n\t\t}\n\t}\n\tcmdPty, err := pty.StartWithSize(ecmd, &pty.Winsize{Rows: uint16(cmdDef.TermSize.Rows), Cols: uint16(cmdDef.TermSize.Cols)})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to start command: %w\", err)\n\t}\n\tunixutil.SetCloseOnExec(int(cmdPty.Fd()))\n\tjm.cmd = ecmd\n\tjm.cmdPty = cmdPty\n\tjm.ptsName = jm.cmdPty.Name()\n\tjm.termSize = cmdDef.TermSize\n\tgo jm.waitForProcess()\n\treturn jm, nil\n}\n\nfunc (jm *JobCmd) waitForProcess() {\n\tif jm.cmd == nil || jm.cmd.Process == nil {\n\t\treturn\n\t}\n\terr := jm.cmd.Wait()\n\tjm.lock.Lock()\n\tdefer jm.lock.Unlock()\n","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobmanager/jobcmd.go#L46-L82","documentation":"After building the exec.Command, MakeJobCmd calls pty.StartWithSize to spawn the process attached to a pseudo-terminal. Any failure from that call (command not found, permission denied, PTY allocation exhaustion) is wrapped as this error.","triggerScenarios":"StartJob with a Cmd that doesn't exist in PATH, isn't executable, an Env list that breaks exec, or the OS can't allocate a new PTY (out of file descriptors / no free ptys).","commonSituations":"Typo in the command name in the job start RPC; running in a container without PTY support or with a low ulimit on ptys; command binary missing after a deployment change.","solutions":["Unwrap the error and check for exec.ErrNotFound / 'permission denied'; fix the Cmd path or chmod +x the binary.","Verify the command exists in PATH within the job manager's environment.","Check pty availability: raise ulimit / kernel pty limits if 'out of pty' errors appear.","Retry StartJob after fixing the environment if it was transient resource exhaustion."],"exampleFix":"// before\nCmd: \"node serve.js\"\n// after\nCmd: \"/usr/local/bin/node\", Args: [\"serve.js\"] // absolute path to an executable binary","handlingStrategy":"validation","validationCode":"// verify the binary is executable before starting the job\nif _, err := exec.LookPath(cmdDef.Cmd); err != nil {\n    return fmt.Errorf(\"command %q not found in PATH: %w\", cmdDef.Cmd, err)\n}","typeGuard":"func cmdStartable(cmd string, args []string) bool {\n    _, err := exec.LookPath(cmd)\n    return err == nil\n}","tryCatchPattern":"cmdPty, err := pty.StartWithSize(ecmd, size)\nif err != nil {\n    if errors.Is(err, exec.ErrNotFound) || errors.Is(err, os.ErrPermission) {\n        // surface a clear 'bad command' message to the user\n    }\n    return fmt.Errorf(\"failed to start command: %w\", err)\n}","preventionTips":["Use absolute paths or verify the command resolves via exec.LookPath before StartJob","Check ulimit -u / pty availability in containerized environments","Ensure the binary has the executable bit and correct interpreter shebang"],"tags":["pty","process","exec"],"backgroundTag":"pty-start-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}