{"record":{"id":"65ba4bbd000a13a9","repo":"wavetermdev/waveterm","slug":"no-active-process","errorCode":null,"errorMessage":"no active process","messagePattern":"no active process","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobmanager/jobcmd.go","lineNumber":122,"sourceCode":"\tif jm.exitCode != nil {\n\t\texitCodeStr = fmt.Sprintf(\"%d\", *jm.exitCode)\n\t}\n\tlog.Printf(\"process exited: exitcode=%s, signal=%s, err=%v\\n\", exitCodeStr, jm.exitSignal, jm.exitErr)\n\n\tgo WshCmdJobManager.sendJobExited()\n}\n\nfunc (jm *JobCmd) GetCmd() (*exec.Cmd, pty.Pty) {\n\tjm.lock.Lock()\n\tdefer jm.lock.Unlock()\n\treturn jm.cmd, jm.cmdPty\n}\n\nfunc (jm *JobCmd) GetPGID() (int, error) {\n\tjm.lock.Lock()\n\tdefer jm.lock.Unlock()\n\tif jm.cmd == nil || jm.cmd.Process == nil {\n\t\treturn 0, fmt.Errorf(\"no active process\")\n\t}\n\tif jm.processExited {\n\t\treturn 0, fmt.Errorf(\"process already exited\")\n\t}\n\tpgid, err := unixutil.GetProcessGroupId(jm.cmd.Process.Pid)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to get pgid: %w\", err)\n\t}\n\tif pgid <= 0 {\n\t\treturn 0, fmt.Errorf(\"invalid pgid returned: %d\", pgid)\n\t}\n\treturn pgid, nil\n}\n\nfunc (jm *JobCmd) GetExitInfo() (bool, *wshrpc.CommandJobCmdExitedData) {\n\tjm.lock.Lock()\n\tdefer jm.lock.Unlock()\n\tif !jm.processExited {","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobmanager/jobcmd.go#L104-L140","documentation":"GetPGID requires a live OS process handle on the job's command. If jm.cmd or jm.cmd.Process is nil, no process was ever started (or the handle was never populated), so the lookup cannot proceed and this error is returned.","triggerScenarios":"Calling GetPGID on a JobCmd before StartJob/MakeJobCmd succeeded, or after the command struct exists but pty.StartWithSize failed so jm.cmd.Process was never set.","commonSituations":"A client querying the process group of a job that failed to launch; a race where GetPGID is called between JobCmd creation and successful start; job object restored from state without a live process.","solutions":["Only call GetPGID after StartJob reports success.","Check the job's running/exited status before querying the pgid.","Guard the call site: skip pgid lookup when the job was never started.","Recreate/restart the job if the handle was lost."],"exampleFix":"// before\npgid, err := jobCmd.GetPGID()\n// after\nif !jobMgr.IsRunning() {\n    return 0, errors.New(\"job not started\")\n}\npgid, err := jobCmd.GetPGID()","handlingStrategy":"validation","validationCode":"// ensure the job was started successfully before querying pgid\nif !jobStartedSuccessfully { // track via StartJob result\n    return errors.New(\"cannot get pgid: job never started\")\n}","typeGuard":"func jobQueryable(jm *jobmanager.JobCmd) bool {\n    _, err := jm.GetExitInfo()\n    return err == nil // job object is live and queryable\n}","tryCatchPattern":"pgid, err := jobCmd.GetPGID()\nif err != nil {\n    if err.Error() == \"no active process\" {\n        return 0, errors.New(\"job was never started; call StartJob first\")\n    }\n    return 0, err\n}","preventionTips":["Only call GetPGID after StartJob returns success","Sequence process-management RPCs after the job-start confirmation event","Never reuse a JobCmd across start failures"],"tags":["process","lifecycle","pgid"],"backgroundTag":"no-active-process","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}