Skip to content

fix(supervisor): suppress unhandled stream errors on child stdout/stderr#99802

Merged
vincentkoc merged 4 commits into
openclaw:mainfrom
cxbAsDev:fix/supervisor-child-stream-error-handlers
Jul 4, 2026
Merged

fix(supervisor): suppress unhandled stream errors on child stdout/stderr#99802
vincentkoc merged 4 commits into
openclaw:mainfrom
cxbAsDev:fix/supervisor-child-stream-error-handlers

Conversation

@cxbAsDev

@cxbAsDev cxbAsDev commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where a supervised child process could crash OpenClaw if stdout or stderr emitted an error after spawn but before the supervisor registered output subscribers.

Why This Change Was Made

The child adapter now installs exactly one stream-lifetime error guard on stdout and stderr during adapter construction. Subscriber registration remains responsible only for decoding data; existing stream close handlers continue to own decoder flush and Windows drain completion.

User Impact

Early child output-stream failures no longer escape as unhandled Node error events. Repeated output subscriptions do not accumulate redundant permanent error listeners, and process wait behavior remains unchanged.

Evidence

  • Focused regression: node scripts/run-vitest.mjs src/process/supervisor/adapters/child.test.ts (19 passed).
  • The test emits errors before output registration, verifies one listener after repeated subscriptions, and proves Windows wait() settles only after stream close.
  • Real Node child-pipe probe confirmed a destroyed output source emits error then close.
  • oxfmt and git diff --check passed.
  • Fresh structured autoreview reported no accepted or actionable findings.
  • Exact prepared head: a968528d469c3b4e1ca1b7701b84854d9f92160b.

Child process stdout and stderr streams can emit 'error' events
(EPIPE, resource limits, I/O errors) that crash the process when
no listener is attached. Add noop error handlers to prevent crashes
while preserving normal data/end/close event flow.

Co-Authored-By: Claude <[email protected]>
@clawsweeper

clawsweeper Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 4, 2026, 1:47 AM ET / 05:47 UTC.

Summary
The PR installs one child stdout/stderr stream error guard during child-adapter setup and adds regression coverage for pre-subscriber stream errors plus Windows close-driven wait settlement.

PR surface: Source +5, Tests +38. Total +43 across 2 files.

Reproducibility: yes. at source level: current main has no child stdout/stderr error listener during adapter construction, while the supervisor registers output subscribers only after createChildAdapter returns. A Node probe also confirms unhandled error events throw unless an error listener is installed.

Review metrics: none identified.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Next step before merge

  • No ClawSweeper repair job is needed because the patch has no blocking findings; remaining action is ordinary maintainer review, CI, and merge gating.

Security
Cleared: The diff only changes child stdout/stderr stream listener handling and a focused test; it does not touch dependencies, CI, package metadata, secrets, permissions, or supply-chain surfaces.

Review details

Best possible solution:

Land the narrow child-adapter lifecycle guard after normal CI and maintainer merge gates, keeping decoder flush and Windows drain settlement owned by the existing close handlers.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: current main has no child stdout/stderr error listener during adapter construction, while the supervisor registers output subscribers only after createChildAdapter returns. A Node probe also confirms unhandled error events throw unless an error listener is installed.

Is this the best way to solve the issue?

Yes: the child adapter is the right owner boundary because it owns the child streams from spawn through wait/dispose, and installing one guard at construction closes the timing gap. Subscriber-level guards were too late, and the PTY sibling is unaffected because it does not expose separate stdout/stderr streams.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 1b84316a91dc.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body and member proof comment provide exact-head validation, including focused regression output, Testbox check:changed proof, and a real Node child-pipe probe observing error then close.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body and member proof comment provide exact-head validation, including focused regression output, Testbox check:changed proof, and a real Node child-pipe probe observing error then close.
  • remove rating: 🧂 unranked krab: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: 📣 needs proof: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: This is a focused supervisor reliability bugfix for a possible process crash path with limited blast radius and no confirmed urgent live-user regression evidence.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body and member proof comment provide exact-head validation, including focused regression output, Testbox check:changed proof, and a real Node child-pipe probe observing error then close.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body and member proof comment provide exact-head validation, including focused regression output, Testbox check:changed proof, and a real Node child-pipe probe observing error then close.
Evidence reviewed

PR surface:

Source +5, Tests +38. Total +43 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 5 0 +5
Tests 1 38 0 +38
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 43 0 +43

What I checked:

  • Current-main gap: Current main creates the child adapter and moves into stdin/setup without stdout/stderr error listeners, so an early stream error can occur before output subscribers attach. (src/process/supervisor/adapters/child.ts:105, 1b84316a91dc)
  • Caller timing: The supervisor awaits createChildAdapter before registering adapter.onStdout and adapter.onStderr, so subscriber-owned guards would not cover the construction window. (src/process/supervisor/supervisor.ts:202, 1b84316a91dc)
  • PR-head implementation: The latest PR head installs one no-op error handler on child.stdout and child.stderr immediately after spawn and before output subscribers attach. (src/process/supervisor/adapters/child.ts:106, a968528d469c)
  • Regression coverage: The new test emits stdout/stderr errors before listeners register, checks repeated subscriptions leave one error listener, and verifies Windows wait remains close-driven. (src/process/supervisor/adapters/child.test.ts:515, a968528d469c)
  • Sibling surface checked: The PTY adapter uses node-pty onData/onExit and has no separate child stdout/stderr streams, so the one-sided child-adapter fix does not need a PTY mirror. (src/process/supervisor/adapters/pty.ts:155, 1b84316a91dc)
  • Node stream behavior probe: Node v24.18.0 throws for an unhandled EventEmitter error event, does not throw once an error listener exists, and a PassThrough destroyed with an error emits error then close.

Likely related people:

  • onutc: The supervisor child adapter, supervisor caller, and initial child-adapter tests were added in the process supervision refactor commit whose message credits @onutc. (role: introduced supervisor feature; confidence: high; commits: cd44a0d01e9f; files: src/process/supervisor/adapters/child.ts, src/process/supervisor/supervisor.ts, src/process/supervisor/adapters/child.test.ts)
  • obviyus: Recent merged commits by this author changed child-adapter Windows stdio drain and exit fallback behavior in the same stream lifecycle path. (role: recent area contributor; confidence: high; commits: c003e982a2df, 063049c0d4de, 4b6b1a3ed358; files: src/process/supervisor/adapters/child.ts, src/process/supervisor/adapters/child.test.ts)
  • steipete: History shows repeated maintenance of child adapter and broader supervisor process behavior, including service-managed child handling and related refactors. (role: recent adjacent owner; confidence: medium; commits: e20f44509924, 344b2286aa72, 273d70741fa1; files: src/process/supervisor/adapters/child.ts, src/process/supervisor/supervisor.ts)
  • vincentkoc: This user is assigned on the PR, authored the latest exact-head repair commit, and posted the maintainer proof comment for the current head. (role: current PR follow-up owner; confidence: medium; commits: a968528d469c; files: src/process/supervisor/adapters/child.ts, src/process/supervisor/adapters/child.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 4, 2026
@vincentkoc vincentkoc self-assigned this Jul 4, 2026
@vincentkoc

Copy link
Copy Markdown
Member

maintainer repair and exact-head proof are complete on a968528d469c3b4e1ca1b7701b84854d9f92160b.

changes:

  • install one stdout/stderr error guard during adapter construction
  • remove subscriber-owned permanent error listeners
  • preserve stream close as the owner of decoder flush and Windows drain completion

validation:

  • node scripts/run-vitest.mjs src/process/supervisor/adapters/child.test.ts (19 passed)
  • real Node child-pipe probe observed error then close
  • fresh autoreview: no accepted/actionable findings
  • OPENCLAW_TESTBOX=1 pnpm check:changed
  • Testbox tbx_01kwnt6mjnb1et43qtby335f6g (exit 0, 3m22s command time)

the PR body now contains the durable lifecycle evidence.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 4, 2026
@vincentkoc
vincentkoc merged commit 3b37fe1 into openclaw:main Jul 4, 2026
124 of 131 checks passed
@vincentkoc

Copy link
Copy Markdown
Member

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 4, 2026
…err (openclaw#99802)

* fix(supervisor): suppress unhandled stream errors on child stdout/stderr

Child process stdout and stderr streams can emit 'error' events
(EPIPE, resource limits, I/O errors) that crash the process when
no listener is attached. Add noop error handlers to prevent crashes
while preserving normal data/end/close event flow.

Co-Authored-By: Claude <[email protected]>

* test(supervisor): add regression test for stream error suppression

Co-Authored-By: Claude <[email protected]>

* fix(supervisor): guard child stream errors during setup

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
@cxbAsDev
cxbAsDev deleted the fix/supervisor-child-stream-error-handlers branch July 15, 2026 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants