wavetermdev/waveterm · error
procinfo: malformed stat for pid %d
Error message
procinfo: malformed stat for pid %d
What it means
The library parsed /proc/<pid>/stat and could not locate a valid comm field: there must be text of the form 'pid (comm) rest...'. It finds the first '(' and last ')'; if either is missing or the ')' does not come after '(', the stat content is considered malformed. This indicates the file did not contain an expected procfs stat record.
Source
Thrown at pkg/util/procinfo/procinfo_linux.go:68
// The comm field (field 2) is enclosed in parentheses and may contain spaces
// and even parentheses itself, so we locate the last ')' to find the field
// boundary rather than splitting on whitespace naively.
func readStat(pid int32) (*ProcInfo, error) {
path := fmt.Sprintf("/proc/%d/stat", pid)
data, err := os.ReadFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("procinfo: read %s: %w", path, err)
}
s := strings.TrimRight(string(data), "\n")
// Locate comm: everything between first '(' and last ')'.
lp := strings.Index(s, "(")
rp := strings.LastIndex(s, ")")
if lp < 0 || rp < 0 || rp <= lp {
return nil, fmt.Errorf("procinfo: malformed stat for pid %d", pid)
}
pidStr := strings.TrimSpace(s[:lp])
comm := s[lp+1 : rp]
rest := strings.Fields(s[rp+1:])
// rest[0] = field 3 (state), rest[1] = field 4 (ppid), ...
// Fields after comm are numbered starting at 3, so rest[i] = field (i+3).
// We need:
// rest[0] = field 3 state
// rest[1] = field 4 ppid
// rest[11] = field 14 utime
// rest[12] = field 15 stime
// rest[17] = field 20 num_threads
// rest[21] = field 24 rss (pages)
if len(rest) < 22 {
return nil, fmt.Errorf("procinfo: too few fields in stat for pid %d", pid)
}View on GitHub (pinned to a4447c1563)
Solutions
- Retry the read — a racing exit usually resolves to ENOENT or a fresh valid read on the next attempt
- Verify /proc/<pid>/stat actually contains a stat line (cat it manually) and that /proc is procfs (mount | grep proc)
- Treat the pid as gone and skip it in monitoring loops
- Check for fixtures/mocks if the failure happens in tests — a stub file without '(comm)' triggers this
Example fix
// before
lp := strings.Index(s, "(")
rp := strings.LastIndex(s, ")")
if lp < 0 || rp < 0 || rp <= lp {
return nil, fmt.Errorf("procinfo: malformed stat for pid %d", pid)
}
// after: tolerate empty/truncated reads as transient
lp := strings.Index(s, "(")
rp := strings.LastIndex(s, ")")
if lp < 0 || rp < 0 || rp <= lp {
if data == nil || len(data) == 0 {
return nil, ErrNotFound // likely raced exit
}
return nil, fmt.Errorf("procinfo: malformed stat for pid %d: %q", pid, s)
} Defensive patterns
Strategy: retry
Validate before calling
// pre-validate the stat line shape before parsing pipelines that depend on it
data, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", pid))
if err == nil && !bytes.Contains(data, []byte("(")) {
// malformed/transient; wait and re-read
} Try / catch
_, err := procinfo.GetProcInfo(ctx, nil, pid)
if err != nil && strings.Contains(err.Error(), "malformed stat") {
// likely transient (racing exit): retry once, then treat pid as gone
time.Sleep(10 * time.Millisecond)
info, err = procinfo.GetProcInfo(ctx, nil, pid)
} Prevention
- Treat malformed stat as a transient condition in monitoring loops
- Ensure /proc is real procfs in containers (not a bind-mounted dir)
- Validate test fixtures contain a full 'pid (comm) ...' line
- Skip-and-log rather than crash when a pid vanishes mid-poll
When it happens
Trigger: Reading a truncated or empty stat file (racing process exit can yield partial content in some kernels/filesystems); the path resolved to something that is not a proc stat file (e.g. procfs not mounted, an overlay exposing a different file); corrupted data from unusual virtualization layers.
Common situations: Flaky reads of a dying process's stat in a process monitor loop; misconfigured containers where /proc is not procfs (e.g. bind-mounted to a regular dir); testing with fake /proc fixtures that lack parentheses.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- procinfo: too few fields in stat for pid %d
- procinfo: parse pid: %w
- procinfo: process not found
- procinfo: read %s: %w
- procinfo: Uid line not found in %s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/1148337d94962e0a.
Report an issue: GitHub.