gastownhall/beads · error
read command line for pid %d: %w
Error message
read command line for pid %d: %w
What it means
On macOS, unverifiedProcess.commandLineContains inspects a PID's arguments by running `ps -p <pid> -o args=`. If ps fails and a follow-up kill(pid,0) shows the process still exists (not ESRCH), the ps failure is wrapped in this error. This keeps the force-stop path safe: the proxy cannot verify what the PID is running, so it refuses to act rather than guessing.
Source
Thrown at internal/storage/dbproxy/proxy/unverified_process_darwin.go:44
if killErr := syscall.Kill(pid, 0); errors.Is(killErr, unix.ESRCH) {
return nil, true, nil
}
return &unverifiedProcess{pid: pid}, false, nil
}
func (p *unverifiedProcess) executableBasename() (basename string, gone bool, err error) {
return processExecutableBasename(p.pid)
}
// commandLineContains reports whether the process command line contains
// needle, read best-effort through ps.
func (p *unverifiedProcess) commandLineContains(needle string) (matched bool, gone bool, err error) {
output, commandErr := exec.Command("ps", "-p", strconv.Itoa(p.pid), "-o", "args=").Output()
if commandErr != nil {
if killErr := syscall.Kill(p.pid, 0); errors.Is(killErr, unix.ESRCH) {
return false, true, nil
}
return false, false, fmt.Errorf("read command line for pid %d: %w", p.pid, commandErr)
}
return strings.Contains(strings.TrimSpace(string(output)), needle), false, nil
}
// kill sends SIGKILL. gone reports a target that had already exited.
func (p *unverifiedProcess) kill() (gone bool, err error) {
if killErr := syscall.Kill(p.pid, syscall.SIGKILL); killErr != nil {
if errors.Is(killErr, unix.ESRCH) {
return true, nil
}
return false, fmt.Errorf("signal pid %d: %w", p.pid, killErr)
}
return false, nil
}
func (p *unverifiedProcess) exited() (bool, error) {
_, gone, err := processExecutableBasename(p.pid)
if err != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Verify /bin/ps works standalone: `ps -p <pid> -o args=` — fix PATH or environment if it fails there.
- Re-run the command; transient fork/exec failures often clear on retry.
- Check whether the process is a zombie (state Z in `ps aux | grep <pid>`); reap the parent or wait for it to exit.
- Manually kill the PID after verifying its identity, then remove the stale pidfile.
Example fix
// before: PATH stripped in daemon env, ps not found PATH=/usr/bin:/bin:/usr/sbin:/sbin bd ... // after: ensure standard paths so exec ps succeeds export PATH="/usr/bin:/bin:/usr/sbin:/sbin:$PATH"
Defensive patterns
Strategy: try-catch
Try / catch
matched, gone, err := proc.commandLineContains(needle)
if err != nil {
if _, statErr := exec.LookPath("ps"); statErr != nil {
// environment problem: fix PATH or inspect the PID manually
}
return fmt.Errorf("cannot verify pid identity, refusing to kill: %w", err)
} Prevention
- Keep /bin/ps available and standard PATH entries intact in daemon/service environments.
- Avoid running bd inside heavily sandboxed exec wrappers that block spawning child processes.
- If ps repeatedly fails, verify PIDs manually with `ps -p <pid> -o args=` before any cleanup.
When it happens
Trigger: commandLineContains runs exec.Command("ps", "-p", pid, "-o", "args=") and it errors while syscall.Kill(pid, 0) does NOT return ESRCH — i.e. ps failed but the process appears alive.
Common situations: Sandboxed/restricted macOS environments where spawning ps fails; ps binary missing from PATH; transient resource exhaustion preventing fork/exec; zombie or system-protected processes ps cannot report on.
Related errors
- dolt version probe failed
- failed to init git in planning repo: %w
- start proxy child: %w
- signal pid %d: %w
- read cmdline for pid %d: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/862b2e4b5edc0890.
Report an issue: GitHub.