pranshuparmar/witr · error
unexpected ps output format for pid %d
Error message
unexpected ps output format for pid %d
What it means
ReadProcess on macOS parses ps output with a strict field layout (pid ppid uid lstart(5 fields) state pcpu rss args...). If the trimmed line has fewer than 11 fields, the output format does not match and parsing is aborted rather than producing garbage. This guards against incompatible or non-standard ps implementations.
Source
Thrown at internal/proc/process_darwin.go:40
// Format: pid(0) ppid(1) uid(2) lstart(3-7) state(8) pcpu(9) rss(10) args(11+)
// ucomm is excluded because it can contain spaces (e.g. "Microsoft Teams"),
// which breaks strings.Fields parsing. The display name is derived from args instead.
cmd := exec.Command("ps", "-p", pidStr, "-o", "pid=,ppid=,uid=,lstart=,state=,pcpu=,rss=,args=")
cmd.Env = buildEnvForPS()
out, err := cmd.Output()
if err != nil {
return model.Process{}, fmt.Errorf("process %d not found: %w", pid, err)
}
line := strings.TrimSpace(string(out))
if line == "" {
return model.Process{}, fmt.Errorf("process %d not found", pid)
}
fields := strings.Fields(line)
if len(fields) < 11 {
return model.Process{}, fmt.Errorf("unexpected ps output format for pid %d", pid)
}
ppid, _ := strconv.Atoi(fields[1])
uid, _ := strconv.Atoi(fields[2])
lstartStr := strings.Join(fields[3:8], " ")
startedAt, _ := time.Parse("Mon Jan 2 15:04:05 2006", lstartStr)
if startedAt.IsZero() {
startedAt = time.Now().UTC()
}
state := fields[8]
cpuPct, _ := strconv.ParseFloat(fields[9], 64)
rssKB, _ := strconv.ParseFloat(fields[10], 64)
rawCmdline := ""
if len(fields) > 11 {View on GitHub (pinned to dc4fa1da82)
Solutions
- Verify `ps -p <pid> -o pid=,ppid=,uid=,lstart=,state=,pcpu=,rss=,args=` on that machine returns the expected columns.
- Ensure the system ps is first in PATH (no BusyBox/wrapper shadowing /usr/bin/ps).
- Run with a standard locale (e.g. LC_ALL=C) to rule out localized formatting.
- Capture the raw ps output to diagnose the actual format and report it if the system ps looks standard.
Example fix
// before LC_ALL=de_DE.UTF-8 witr <pid> // after LC_ALL=C witr <pid>
Defensive patterns
Strategy: validation
Validate before calling
// sanity-check ps output format in your environment once at startup
out, _ := exec.Command("ps", "-p", "1", "-o", "pid=,ppid=,uid=,lstart=,state=,pcpu=,rss=,args=").Output()
if out != nil && len(strings.Fields(strings.TrimSpace(string(out)))) < 11 {
// non-standard ps detected; don't rely on ReadProcess
} Try / catch
proc, err := proc.ReadProcess(pid)
if err != nil {
if strings.Contains(err.Error(), "unexpected ps output format") {
// environment problem: check ps variant/locale before retrying
}
} Prevention
- Standardize locale (LC_ALL=C) for processes spawning ps
- Verify /usr/bin/ps is not shadowed by BusyBox/toybox/wrappers
- Smoke-test the ps -o format on target machines before deployment
When it happens
Trigger: ReadProcess encountering ps output with < 11 whitespace-separated fields — a ps variant that ignores the -o format spec, locale/localized output, or truncated/aliased ps output.
Common situations: Environments with BusyBox/toybox ps or a shimmed ps in PATH; locale settings changing column formatting; a ps wrapper that reformats output.
Related errors
- unexpected ps output format for pid %d: got %d fields in %q
- listfds returned partial record
- launchctl blame failed: %w
- no service label found for pid %d
- process not managed by a named launchd service: %s
AI-assisted analysis of pranshuparmar/witr@dc4fa1da82 (2026-09-01).
Data as JSON: /api/errors/a4f2cdd6c3d04023.
Report an issue: GitHub.