{"record":{"id":"895515b31c5cafa5","repo":"gastownhall/beads","slug":"procid-process-is-no-longer-running-w","errorCode":null,"errorMessage":"procid: process is no longer running: %w","messagePattern":"procid: process is no longer running: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/procid/procid_linux.go","lineNumber":212,"sourceCode":"\tif err != nil {\n\t\treturn \"\", &processStatReadError{pid: pid, err: err}\n\t}\n\treturn parseStartTime(string(data))\n}\n\nfunc parseStartTime(stat string) (string, error) {\n\tendComm := strings.LastIndex(stat, \")\")\n\tif endComm == -1 {\n\t\treturn \"\", errors.New(\"procid: malformed proc stat: missing comm terminator\")\n\t}\n\tfields := strings.Fields(stat[endComm+1:])\n\t// The remainder starts with state (field 3), so starttime (field 22) is\n\t// its twentieth field.\n\tif len(fields) < 20 {\n\t\treturn \"\", errors.New(\"procid: malformed proc stat: missing starttime\")\n\t}\n\tif fields[0] == \"Z\" || fields[0] == \"X\" || fields[0] == \"x\" {\n\t\treturn \"\", fmt.Errorf(\"procid: process is no longer running: %w\", unix.ESRCH)\n\t}\n\tif _, err := strconv.ParseUint(fields[19], 10, 64); err != nil {\n\t\treturn \"\", fmt.Errorf(\"procid: malformed proc stat starttime: %w\", err)\n\t}\n\treturn fields[19], nil\n}\n\ntype bootIDReadError struct {\n\tpath string\n\terr  error\n}\n\nfunc (e *bootIDReadError) Error() string {\n\treturn fmt.Sprintf(\"procid: read boot ID %s: %v\", e.path, e.err)\n}\n\ntype processStatReadError struct {\n\tpid int","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/procid/procid_linux.go#L194-L230","documentation":"parseStartTime parses field 22 (starttime) from /proc/<pid>/stat to build a process-birth identity token. When the state field (field 3) is 'Z' (zombie), 'X', or 'x' (dead), the process has exited, so the function returns this error wrapping unix.ESRCH — the conventional 'no such process' signal that the target is gone rather than malformed.","triggerScenarios":"Calling Capture or processStartTime on a PID that has already exited and been reaped or is awaiting reap (zombie); a race where the process dies between opening /proc/<pid>/stat and reading it; verifying a token against a stale PID whose owner is now a zombie.","commonSituations":"Parent process has not wait()ed yet so child lingers as zombie; worker pool reaping races; health checks probing a PID that just exited; kill-then-verify flows where verify lands after exit.","solutions":["Treat errors.Is(err, unix.ESRCH) as 'process is gone' and take the dead-process branch (do not retry)","If a zombie is unexpected, have the parent call wait()/waitpid() to reap it, then re-check","Re-run Capture after confirming the PID is live (e.g. after reaping) if you need a fresh token"],"exampleFix":"// before\ntok, err := procid.Capture(pid)\nif err != nil {\n\treturn err\n}\n// after\ntok, err := procid.Capture(pid)\nif errors.Is(err, unix.ESRCH) {\n\treturn nil // process already exited; nothing to do\n}\nif err != nil {\n\treturn err\n}","handlingStrategy":"type-guard","validationCode":"func processExists(pid int) bool {\n\t_, err := os.Stat(fmt.Sprintf(\"/proc/%d/stat\", pid))\n\treturn err == nil\n}","typeGuard":"func isProcessGone(err error) bool {\n\treturn errors.Is(err, unix.ESRCH) || errors.Is(err, os.ErrNotExist)\n}","tryCatchPattern":"tok, err := procid.Capture(pid)\nif isProcessGone(err) {\n\treturn handleExitedProcess(pid) // reap via wait() if you are the parent\n}\nif err != nil {\n\treturn fmt.Errorf(\"capture pid %d: %w\", pid, err)\n}","preventionTips":["If you are the parent, wait()/waitpid() promptly to avoid zombie children","Re-check liveness (kill(pid,0) or /proc stat) immediately before Capture","Treat ESRCH as a normal exit condition, not a failure to log at error level","Design flows so token capture happens immediately after spawning to minimize exit races"],"tags":["linux","process-management","esrch","zombie-process"],"backgroundTag":"process-not-found-esrch","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}