gastownhall/beads · warning
procid: malformed proc stat: missing starttime
Error message
procid: malformed proc stat: missing starttime
What it means
parseStartTime splits everything after the comm terminator ')' into fields. The remainder starts with state (field 3 of stat), so starttime (field 22) is the 20th token. This error means the post-comm portion had fewer than 20 fields, i.e. the stat line was truncated before starttime.
Source
Thrown at internal/procid/procid_linux.go:209
func processStartTime(pid int) (string, error) {
data, err := os.ReadFile("/proc/" + strconv.Itoa(pid) + "/stat")
if err != nil {
return "", &processStatReadError{pid: pid, err: err}
}
return parseStartTime(string(data))
}
func parseStartTime(stat string) (string, error) {
endComm := strings.LastIndex(stat, ")")
if endComm == -1 {
return "", errors.New("procid: malformed proc stat: missing comm terminator")
}
fields := strings.Fields(stat[endComm+1:])
// The remainder starts with state (field 3), so starttime (field 22) is
// its twentieth field.
if len(fields) < 20 {
return "", errors.New("procid: malformed proc stat: missing starttime")
}
if fields[0] == "Z" || fields[0] == "X" || fields[0] == "x" {
return "", fmt.Errorf("procid: process is no longer running: %w", unix.ESRCH)
}
if _, err := strconv.ParseUint(fields[19], 10, 64); err != nil {
return "", fmt.Errorf("procid: malformed proc stat starttime: %w", err)
}
return fields[19], nil
}
type bootIDReadError struct {
path string
err error
}
func (e *bootIDReadError) Error() string {
return fmt.Sprintf("procid: read boot ID %s: %v", e.path, e.err)
}View on GitHub (pinned to 71377f2769)
Solutions
- Retry the read once — truncation is almost always a transient exit race
- Treat persistent failure as process-gone (the parser already maps Z/X/x states to ESRCH) and fall back to a liveness check via signal 0 or os.Stat on /proc/<pid>
- Log the raw stat content to confirm it is genuinely truncated rather than a parser bug
- Avoid caching stat contents; always re-read freshly per call
Example fix
// before
start, err := processStartTime(pid) // fails with missing starttime on racing exit
if err != nil { return err }
// after
start, err := processStartTime(pid)
if err != nil {
if errors.Is(err, unix.ESRCH) || strings.Contains(err.Error(), "malformed proc stat") {
return ErrProcessGone // treat as exited, retry discovery
}
return err
} Defensive patterns
Strategy: retry
Validate before calling
data, err := os.ReadFile(fmt.Sprintf("/proc/%d/stat", pid)); if err == nil && strings.Count(string(data), " ") >= 21 { /* likely complete */ } Type guard
func isMissingStarttime(err error) bool { return strings.Contains(err.Error(), "missing starttime") } Try / catch
start, err := processStartTime(pid)
if err != nil {
if isMissingStarttime(err) { return ErrProcessGone } // exit race: treat as gone
return err
} Prevention
- Treat parse failures on /proc stat as potential process-exit races
- Fall back to a liveness check (signal 0 / os.Stat) on parse failure
- Avoid bulk scans that hold stale PID lists while processes churn
- Log the raw stat line once to distinguish truncation from parser bugs
When it happens
Trigger: Calling processStartTime on a process that exited or is being reaped while /proc/<pid>/stat is read, yielding a partial line; reading a stat file whose content was cut short by a concurrent kernel update.
Common situations: Bulk PID scans over /proc racing with process churn; test suites spawning and killing processes rapidly; filesystem snapshots or overlays exposing partial procfs content.
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
- procid: malformed proc stat: missing comm terminator
- server: DoltServer.Start: capture child birth identity: %w
- procid: process %d still matches token after fatal signal an
- procid: process is no longer running: %w
- procid: malformed proc stat starttime: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/bdd72f294e4f49af.
Report an issue: GitHub.