{"record":{"id":"3a35bc2e111d8d74","repo":"wavetermdev/waveterm","slug":"procinfo-process-not-found","errorCode":null,"errorMessage":"procinfo: process not found","messagePattern":"procinfo: process not found","errorType":"error_code","errorClass":"ErrNotFound","httpStatus":null,"severity":"warning","filePath":"pkg/util/procinfo/procinfo.go","lineNumber":9,"sourceCode":"// Copyright 2026, Command Line Inc.\n// SPDX-License-Identifier: Apache-2.0\n\npackage procinfo\n\nimport \"errors\"\n\n// ErrNotFound is returned by GetProcInfo when the requested pid does not exist.\nvar ErrNotFound = errors.New(\"procinfo: process not found\")\n\n// LinuxStatStatus maps the single-character state from /proc/[pid]/stat to a human-readable name.\nvar LinuxStatStatus = map[string]string{\n\t\"R\": \"running\",\n\t\"S\": \"sleeping\",\n\t\"D\": \"disk-wait\",\n\t\"Z\": \"zombie\",\n\t\"T\": \"stopped\",\n\t\"t\": \"tracing-stop\",\n\t\"W\": \"paging\",\n\t\"X\": \"dead\",\n\t\"x\": \"dead\",\n\t\"K\": \"wakekill\",\n\t\"P\": \"parked\",\n\t\"I\": \"idle\",\n}\n\n// ProcInfo holds per-process information read from the OS.","sourceCodeStart":1,"sourceCodeEnd":27,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/util/procinfo/procinfo.go#L1-L27","documentation":"procinfo.ErrNotFound is returned by GetProcInfo (and its helpers readStat/readUid) when the requested pid does not exist — i.e. /proc/<pid>/stat or /proc/<pid>/status cannot be read because the process is gone or never existed. It is a sentinel error so callers can use errors.Is to distinguish 'no such process' from other I/O failures.","triggerScenarios":"Calling procinfo.GetProcInfo(pid) for a pid that has exited, is not owned/readable, or never existed; EnsureInitialData/InitMainServer polling a process that terminated between listing and reading its /proc entries.","commonSituations":"Race between finding a pid (e.g. from a child process spawn) and querying its info; short-lived worker processes that exit before status is read; querying pids from a stale process list; running in a container where /proc of the host is restricted.","solutions":["Use errors.Is(err, procinfo.ErrNotFound) to detect the missing-process case and handle it as an expected outcome.","Retry once after a short delay if the process was just spawned — it may not have been fully registered yet.","Verify the pid is still alive (e.g. signal 0 or /proc/<pid> existence) before calling GetProcInfo.","Check permissions: if /proc/<pid>/stat is unreadable due to ownership, the same sentinel may surface."],"exampleFix":"// before\ninfo, err := procinfo.GetProcInfo(pid)\nif err != nil {\n    return err\n}\n// after\ninfo, err := procinfo.GetProcInfo(pid)\nif errors.Is(err, procinfo.ErrNotFound) {\n    return nil // process already exited\n}\nif err != nil {\n    return err\n}","handlingStrategy":"type-guard","validationCode":"if _, err := os.Stat(fmt.Sprintf(\"/proc/%d/stat\", pid)); os.IsNotExist(err) {\n    // pid already gone; skip GetProcInfo\n}","typeGuard":"func isProcNotFound(err error) bool { return errors.Is(err, procinfo.ErrNotFound) }","tryCatchPattern":"info, err := procinfo.GetProcInfo(pid)\nif errors.Is(err, procinfo.ErrNotFound) {\n    return nil // expected race: process exited\n}\nif err != nil {\n    return err // real I/O or permission failure\n}","preventionTips":["Never assume a pid observed earlier is still alive; /proc entries vanish instantly on exit.","Always branch on errors.Is(err, procinfo.ErrNotFound) before generic error handling.","Add a small retry for very recently spawned pids.","Log the pid with the failure to distinguish races from permission issues."],"tags":["go","linux","procfs","process","sentinel-error"],"backgroundTag":"process-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}