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

  1. Verify `ps -p <pid> -o pid=,ppid=,uid=,lstart=,state=,pcpu=,rss=,args=` on that machine returns the expected columns.
  2. Ensure the system ps is first in PATH (no BusyBox/wrapper shadowing /usr/bin/ps).
  3. Run with a standard locale (e.g. LC_ALL=C) to rule out localized formatting.
  4. 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

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


AI-assisted analysis of pranshuparmar/witr@dc4fa1da82 (2026-09-01). Data as JSON: /api/errors/a4f2cdd6c3d04023. Report an issue: GitHub.