pranshuparmar/witr · error

invalid pid %d

Error message

invalid pid %d

What it means

On macOS, ReadProcess shells out to `ps` and refuses to run at all for non-positive PIDs. PID 0 is the kernel and negative values are never valid userland PIDs, so there is nothing to read. The error is a pure input-validation guard.

Source

Thrown at internal/proc/process_darwin.go:19

//go:build darwin

package proc

import (
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/pranshuparmar/witr/pkg/model"
)

func ReadProcess(pid int) (model.Process, error) {
	if pid <= 0 {
		return model.Process{}, fmt.Errorf("invalid pid %d", pid)
	}
	pidStr := strconv.Itoa(pid)

	// 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)
	}

View on GitHub (pinned to dc4fa1da82)

Solutions

  1. Check the pid value at the call site; fix the source that produced 0/negative.
  2. Treat pid 0 as 'unknown process' in your logic and skip the ReadProcess call.
  3. Validate PID > 0 before invoking witr APIs.

Example fix

// before
proc, err := proc.ReadProcess(parentPid) // parentPid == 0
// after
if parentPid > 0 {
    proc, err = proc.ReadProcess(parentPid)
}
Defensive patterns

Strategy: validation

Validate before calling

if pid <= 0 {
    return fmt.Errorf("cannot read process: pid %d is invalid", pid)
}

Try / catch

proc, err := proc.ReadProcess(pid)
if err != nil {
    if strings.Contains(err.Error(), "invalid pid") {
        // caller bug: fix the PID source rather than retrying
    }
}

Prevention

When it happens

Trigger: Calling ReadProcess (directly or via pidIdentityChanged) with pid <= 0 — e.g. an uninitialized pid variable, a zero value from a struct field, or a sentinel used to mean 'no process'.

Common situations: Caller populates the PID from a lookup that returned nothing and passes 0 through; code paths that haven't discovered the parent yet and pass 0 as the parent PID.

Related errors


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