code-yeongyu / code-yeongyu/senpi

[Bug]: shared RPC host (--mode rpc --multi) never reaps its ps children - 9,386 zombies filled the macOS process table and every spawn on the machine failed with EAGAIN

Closed
#1,507 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
429
Forks
98
Avg merge
5h 3m
Merged PRs (30d)
526

Description

## Incident

2026-09-09 ~01:00 KST on mengmotaHost (macOS 26.4.1, bun 1.4.2, global `omo-ai@5.0.0-0.beta.48` = senpi 2026.9.7-2): every process on the machine started failing with `EAGAIN: resource temporarily unavailable` on `posix_spawn` - shells, `gh`, `ps`, the omo eval kernels, even `/usr/bin/true`. The kernel process table held **10,981 entries, 9,750 of them zombies**.

Forensics were taken without spawning anything (bun:ffi over `sysctl KERN_PROC_ALL` / libproc):

- 9,386 of the zombies had `p_comm = ps`; the rest were 334 Chromium helpers from unrelated browser sessions.
- All `ps` zombies had one of six parents, every one of them a senpi shared RPC host from the global install:
`/Users/yeongyu/.bun/bin/bun ~/.bun/install/global/node_modules/@code-yeongyu/senpi/dist/cli.js --extension ~/.bun/install/global/node_modules/omo-ai/plugin --mode rpc --multi`
with 2097, 2097, 1324, 1322, 1319 and 1227 zombie children respectively (parent chains: `bun <- bun <- bun <- bun`, i.e. omo TUI sessions' senpi-task hosts).
- The desktop's socket hosts (`omo --mode rpc --multi-session --listen`, ~/omo-desktop-runtime) had **0** zombies each, so the leak is specific to the `--mode rpc --multi` host process.
- The only `ps` invocation that shape reaches inside that host is the omo plugin's process-identity probe `/bin/ps -o lstart= -p ` (`execFile` from `node:child_process`; used by memory locks, reflection/facts reservations and lock recovery, so it runs continuously). A 30x `execFile("/bin/ps")` micro-repro from a plain bun 1.4.0 main thread and from a `Worker` thread reaps normally (1 transient zombie), so the unreaped state depends on something the `--multi` host does (SIGCHLD handling, worker admission introduced by #1499's predecessor, or the 1.4.2 runtime) - not yet isolated.

Recovery: `kill(pid, SIGTERM)` on the six hosts via ffi; the zombies were reparented to launchd and reaped within seconds (10,981 -> 1,578 processes), and `posix_spawn` worked again. The owning omo sessions respawn their host on demand.

## Why this matters

A single long-lived TUI session with senpi-task takes the whole machine down after a few hours: the host never `waitpid`s its `ps` children, and macOS `kern.maxproc` is shared by every user process. Nothing else on the box can fork once the table is full, which is exactly the failure mode that hit this session (monitors dying with exit 128, PTY allocation failing).

## Next

1. Reproduce on a live `--mode rpc --multi` host: count zombie children per minute (`sysctl KERN_PROC_ALL` parse, or `ps -o stat= -p`) while the omo plugin's memory workers run; identify whether the identity probe or another spawner leaks, and whether the leak needs bun 1.4.2.
2. Fix at the source (reap or never leave a subprocess handle unobserved; a `SIGCHLD`/`waitpid` sweep in the host as defence in depth).
3. Regression guard: a host-level test that spawns N short children through the same path and asserts zero zombies after they exit.

A watcher is running on the affected machine (5-minute `sysctl` scan, alerts at 50+ zombies per parent) so a recurrence is caught before the table fills again.

Contributor guide

Open the contributing guide

Research direction

Start at the shared host entry point in dist/cli.js for --mode rpc --multi, then trace the omo plugin's /bin/ps identity probe through node:child_process execFile. Reproduce while memory workers run and determine which path leaves zombie children, including whether bun 1.4.2 matters. Done means a host-level regression test observes zero zombies after repeated short-child executions.

Written by the indexing model from the issue text.

Assessment

Tech stack
bun, node.js, typescript
Domain
backend, cli, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.