fix(coding-agent): surface the real spawn error when the daemon cannot launch a worker - #1918
Merged
Conversation
…eate errors When the daemon hits its fd limit, spawn fails with EMFILE and leaves child.stdio undefined; launchWorker crashed with a raw TypeError that masked the real error and reached the client as an unhandled throw with a stack dump. - daemon-supervisor: race the child spawn/error events so a failed spawn deterministically fails the create with the real spawn error, enriched with the resident worker count and a ulimit hint for EMFILE/ENFILE. - CLI: wrap generic daemon create failures in DaemonSessionCreateError and handle it at both createDaemonClientConnection call-site boundaries as a one-line error with exit code 1.
…kills errno-unconditional-hint mutant)
xeophon
approved these changes
Aug 31, 2026
PR9000
pushed a commit
to PR9000/prime-agent
that referenced
this pull request
Sep 1, 2026
…t launch a worker (PrimeIntellect-ai#1918) * fix(coding-agent): surface worker spawn failures (EMFILE) as clean create errors When the daemon hits its fd limit, spawn fails with EMFILE and leaves child.stdio undefined; launchWorker crashed with a raw TypeError that masked the real error and reached the client as an unhandled throw with a stack dump. - daemon-supervisor: race the child spawn/error events so a failed spawn deterministically fails the create with the real spawn error, enriched with the resident worker count and a ulimit hint for EMFILE/ENFILE. - CLI: wrap generic daemon create failures in DaemonSessionCreateError and handle it at both createDaemonClientConnection call-site boundaries as a one-line error with exit code 1. * test(coding-agent): assert spawn-failure hint is EMFILE/ENFILE-only (kills errno-unconditional-hint mutant) * chore(coding-agent): trim comments in the spawn-failure change
ketema
added a commit
to ketema/prime-agent
that referenced
this pull request
Sep 1, 2026
- Direct session transport between TUI and worker (ENG-5817, PrimeIntellect-ai#1926) - Event-driven supervisor agent roster with push subscriptions (PrimeIntellect-ai#1897, PrimeIntellect-ai#1900, PrimeIntellect-ai#1895) - Hardened daemon startup, recovery ownership, and worker launch diagnostics (PrimeIntellect-ai#1929, PrimeIntellect-ai#1918) - Python REPL runtime single-dump snapshots and bash preview tool (PrimeIntellect-ai#1945, PrimeIntellect-ai#1911) - Non-blocking RLM subagent deletion and snapshot update suppression (PrimeIntellect-ai#1954, PrimeIntellect-ai#1944) - Saved catalog loading on Agents View open (PrimeIntellect-ai#1960) - Advanced Anthropic prompt caching marker across tool results (PrimeIntellect-ai#1927) - TUI process replacement on update and empty draft eviction (PrimeIntellect-ai#1631, PrimeIntellect-ai#1946, PrimeIntellect-ai#1920)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On macOS the daemon inherits the first client's file-descriptor soft limit (default 256). Each detached session keeps a resident worker (+2 daemon fds), so heavy multi-session use eventually makes worker
spawn()fail withEMFILE. On that failure Node returns a ChildProcess withpid=undefinedandstdio=undefined, andlaunchWorkerdereferencedchild.stdio[WORKER_STARTUP_GATE_FD]synchronously:The TypeError masked the real error, was sent to the client as the create failure, and crashed the client with a raw Node stack dump. Users saw "after a couple of sessions it can't create a new one" with no clue that killing resident workers (freeing fds) was the fix.
The fix
launchWorkerawaits aspawnSettledrace of the child'sspawnvserrorevents before touching stdio. A failed spawn now rejects the create with the real spawn error, plus - forEMFILE/ENFILE- the resident worker count and a hint (stop unused sessions or raise the open-file limit (ulimit -n)). Other errnos (e.g.ENOENT) keep their message without the fd hint. On successstdiois populated synchronously before the await, so the healthy path is unchanged; failure cleanup rides the existing close/catch path (verified for both the EMFILE shape,stdio=undefined, and the ENOENT shape, live gate stream destroyed).DaemonSessionCreateErrorand are handled at the two existing call-site boundaries - one red line, exit 1 - instead of escapingrunClias an unhandled stack dump. Responses with typederrorInfo(e.g.session_already_active) pass through unwrapped, keeping their dedicated handling.Both failure shapes were probed against real Node on macOS (
ulimit -n 64) rather than assumed; the supervisor test's fake child mirrors that verified shape, and the pre-fix test run reproduced the exact production TypeError.Linear: ENG-5808
Note
Medium Risk
Touches daemon worker launch and CLI error boundaries; behavior change is intentional (fail fast with clear messages) but alters how create failures surface to callers.
Overview
Fixes daemon session create when worker
spawn()fails (e.g. EMFILE from too many resident workers): users previously saw a masked TypeError on undefinedchild.stdioand an unhandled CLI stack dump instead of the real spawn error.Supervisor (
launchWorker) now waits for the childspawnorerrorevent before touching stdio, rejects create with the actual spawn message, and for EMFILE/ENFILE appends resident worker count plus a hint to stop sessions or raiseulimit -n.Client deserializes untyped create failures as
DaemonSessionCreateError(typederrorInforesponses still map to existing errors likeSessionAlreadyActiveError).main.tscatches that at interactive and RPC create paths, prints one red error line, and exits 1.Reviewed by Cursor Bugbot for commit 01d9643. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix CLI crash when daemon cannot spawn a worker, surfacing the real error
DaemonSupervisor.launchWorkernow awaits aspawnSettledpromise before accessingchild.stdio, so failed spawns (e.g. EMFILE) throw a clear error instead of crashing later on undefined stdiodescribeWorkerSpawnFailurewhich appends a resident-worker count andulimit -nhint for EMFILE/ENFILE errorsDaemonSessionCreateErroranddeserializeDaemonCreateErrorso generic daemon create failures are deserialized into a distinct error type that the CLI can handleDaemonSessionCreateErrorat session creation and prints a single-line error with exit code 1 instead of rethrowing a stack tracecreateDaemonClientConnectionnow receiveDaemonSessionCreateErrorfor untyped create failures instead of a genericErrorMacroscope summarized 01d9643.