{"record":{"id":"a6832b172fc34af8","repo":"wavetermdev/waveterm","slug":"invalid-pgid-returned-d","errorCode":null,"errorMessage":"invalid pgid returned: %d","messagePattern":"invalid pgid returned: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/jobmanager/jobcmd.go","lineNumber":132,"sourceCode":"\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 {\n\t\treturn false, nil\n\t}\n\texitData := &wshrpc.CommandJobCmdExitedData{\n\t\tJobId:      WshCmdJobManager.JobId,\n\t\tExitCode:   jm.exitCode,\n\t\tExitSignal: jm.exitSignal,\n\t\tExitTs:     jm.exitTs,\n\t}\n\tif jm.exitErr != nil {\n\t\texitData.ExitErr = jm.exitErr.Error()","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/jobmanager/jobcmd.go#L114-L150","documentation":"After a successful GetProcessGroupId call, GetPGID sanity-checks that the returned pgid is positive. A zero or negative value would be nonsensical, so it is rejected with this error — indicating an unexpected kernel/utility-layer response.","triggerScenarios":"unixutil.GetProcessGroupId returns a non-positive value despite reporting success — essentially only from a broken platform implementation or an unexpected syscall result.","commonSituations":"Porting to a new OS/platform where the pgid lookup shim returns 0 on success; a stubbed or mocked unixutil in tests.","solutions":["Inspect the unixutil.GetProcessGroupId implementation for the current platform and fix the return-value handling.","Log the pid/pgid pair and report a bug if a real kernel returned pgid <= 0.","Fall back to treating the process's pid as its group leader when the lookup misbehaves.","Add a unit test asserting positive pgid on each supported platform."],"exampleFix":"// before\npgid, err := unixutil.GetProcessGroupId(pid)\nreturn pgid, err\n// after\npgid, err := unixutil.GetProcessGroupId(pid)\nif pgid <= 0 {\n    return 0, fmt.Errorf(\"invalid pgid returned: %d\", pgid)\n}\nreturn pgid, err","handlingStrategy":"type-guard","validationCode":"func sanePGID(pgid int) bool { return pgid > 0 }","typeGuard":"func isValidPGID(pgid int, ok bool) bool {\n    return ok && pgid > 0\n}","tryCatchPattern":"pgid, err := jobCmd.GetPGID()\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid pgid returned\") {\n        // platform bug: fall back to treating pid as pgid\n        return jobCmd.PID()\n    }\n    return err\n}","preventionTips":["Unit-test unixutil.GetProcessGroupId on every supported platform","Don't stub the pgid lookup with zero-returning mocks in tests","Log pid and pgid together to catch platform regressions early"],"tags":["pgid","unix","platform"],"backgroundTag":"invalid-process-group-id","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}