{"record":{"id":"72e66581c0606dde","repo":"wavetermdev/waveterm","slug":"procinfo-read-s-w","errorCode":null,"errorMessage":"procinfo: read %s: %w","messagePattern":"procinfo: read (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/util/procinfo/procinfo_linux.go","lineNumber":60,"sourceCode":"\t} else if errors.Is(err, ErrNotFound) {\n\t\treturn nil, ErrNotFound\n\t}\n\treturn info, nil\n}\n\n// readStat parses /proc/[pid]/stat.\n//\n// The comm field (field 2) is enclosed in parentheses and may contain spaces\n// and even parentheses itself, so we locate the last ')' to find the field\n// boundary rather than splitting on whitespace naively.\nfunc readStat(pid int32) (*ProcInfo, error) {\n\tpath := fmt.Sprintf(\"/proc/%d/stat\", pid)\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\t\treturn nil, fmt.Errorf(\"procinfo: read %s: %w\", path, err)\n\t}\n\ts := strings.TrimRight(string(data), \"\\n\")\n\n\t// Locate comm: everything between first '(' and last ')'.\n\tlp := strings.Index(s, \"(\")\n\trp := strings.LastIndex(s, \")\")\n\tif lp < 0 || rp < 0 || rp <= lp {\n\t\treturn nil, fmt.Errorf(\"procinfo: malformed stat for pid %d\", pid)\n\t}\n\n\tpidStr := strings.TrimSpace(s[:lp])\n\tcomm := s[lp+1 : rp]\n\trest := strings.Fields(s[rp+1:])\n\n\t// rest[0] = field 3 (state), rest[1] = field 4 (ppid), ...\n\t// Fields after comm are numbered starting at 3, so rest[i] = field (i+3).\n\t// We need:\n\t//   rest[0]  = field  3  state","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/util/procinfo/procinfo_linux.go#L42-L78","documentation":"os.ReadFile of /proc/<pid>/stat failed with an error other than ENOENT (which is mapped to ErrNotFound instead). This is a wrapped I/O error, typically EACCES or EIO. The procinfo package surfaces the underlying errno via %w so callers can errors.Is/errors.As it.","triggerScenarios":"GetProcInfo on Linux when /proc/<pid>/stat exists but cannot be read: EACCES from hidepid=2/3 proc mounts, or the process exited mid-read producing an unusual error (not ENOENT).","commonSituations":"Systems mounting /proc with hidepid=1/2 and the caller not in the proc group; restricted containers (Docker without pid namespace access); SELinux/AppArmor denials; attempting to read a kernel-thread pid from a restricted context.","solutions":["Check the wrapped errno with errors.Is(err, fs.ErrPermission); if EACCES, run as root or in the same user/proc group as the target","On hidepid mounts, add the reader to the proc group (group= option of /proc mount) or mount /proc without hidepid","If the error is ESRCH/ENOENT-like because the process died, treat it as process-not-found rather than fatal","Confirm you are on real Linux with /proc mounted (procfs), not a stripped container","Check LSM logs (dmesg / auditd) for SELinux/AppArmor denials and add allow rules"],"exampleFix":"// caller-side\ngot, err := procinfo.GetProcInfo(ctx, nil, pid)\nvar perr *fs.PathError\nif err != nil && errors.As(err, &perr) && errors.Is(perr.Err, os.ErrPermission) {\n    // hidepid/permission issue: fall back to elevated reader\n}","handlingStrategy":"try-catch","validationCode":"// Go: ensure the process exists and is readable before calling\nif _, err := os.Stat(fmt.Sprintf(\"/proc/%d/stat\", pid)); err != nil {\n    // missing or unreadable; resolve permissions first\n}","typeGuard":null,"tryCatchPattern":"info, err := procinfo.GetProcInfo(ctx, nil, pid)\nvar perr *fs.PathError\nif err != nil {\n    if errors.As(err, &perr) && errors.Is(perr.Err, os.ErrPermission) {\n        // EACCES from hidepid/LSM: fall back to elevated reader or skip\n    }\n    return err\n}","preventionTips":["Avoid hidepid=2 unless the reader is in the proc group","Run monitoring agents under the same uid as monitored processes","Unwrap with errors.Is/errors.As to distinguish permission vs other I/O failures","Check audit logs for LSM denials in hardened environments"],"tags":["linux","procfs","permissions","io-error"],"backgroundTag":"proc-read-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}