Skip to content

fix(imessage): handle stdout/stderr stream errors in the RPC client child#101084

Merged
steipete merged 3 commits into
openclaw:mainfrom
masatohoshino:fix/imessage-client-stream-error
Jul 7, 2026
Merged

fix(imessage): handle stdout/stderr stream errors in the RPC client child#101084
steipete merged 3 commits into
openclaw:mainfrom
masatohoshino:fix/imessage-client-stream-error

Conversation

@masatohoshino

@masatohoshino masatohoshino commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

The long-lived imsg monitor client handled errors from the child process itself, but not from its stdin/stdout/stderr streams. Node treats an unhandled error event as fatal, and a terminal stream failure could also leave pending RPC requests and waitForClose() unresolved.

Why This Change Was Made

Route child-process and stdio errors through one idempotent terminal path. The path rejects every pending request, resolves the close promise exactly once, and terminates the unusable child with SIGTERM. This preserves the monitor provider's existing cleanup contract: it awaits waitForClose() before stopping the active client.

The original contributor patch identified the missing listeners. The maintainer refactor makes those listeners participate in the client's lifecycle instead of only suppressing an uncaught event.

User Impact

An imsg monitor whose child pipe fails now shuts down predictably instead of crashing the host process or hanging its monitor loop indefinitely.

Evidence

Known gap: this uses the real Node process/stream lifecycle but does not deliberately fault a live Messages transport session.

Thanks @masatohoshino for finding and fixing this failure mode.

…hild

A dead imsg RPC helper can emit an async error on any of its stdio streams.
On a raw stream an unhandled 'error' event throws and surfaces as an
uncaughtException, crashing the gateway. openclaw#75438 added this guard for stdin
but left stdout/stderr — on the same long-lived child — unguarded.

Route stdout/stderr stream errors through the existing failAll path via a
shared failFromStreamError helper, mirroring the stdin handler. Add a
regression test that emits 'error' on each stream and asserts the child does
not throw and in-flight requests reject cleanly.
@openclaw-barnacle openclaw-barnacle Bot added channel: imessage Channel integration: imessage size: S labels Jul 6, 2026
@clawsweeper

clawsweeper Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 6, 2026, 10:11 PM ET / 02:11 UTC.

Summary
The branch routes iMessage RPC child process and stdio stream errors through one terminal finish path, sends SIGTERM to the failed helper, and adds regression coverage for mocked and real child stdout failures.

PR surface: Source +17, Tests +115. Total +132 across 2 files.

Reproducibility: yes. source-reproducible with high confidence: current main has stdout/stderr data handlers but no stdout/stderr error listeners, and a Node EventEmitter probe confirms unhandled error events throw. I did not run a full live imsg gateway reproduction in this read-only review.

Review metrics: none identified.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof from a real setup is added.

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

Rank-up moves:

  • [P1] Add redacted terminal output, logs, or a short transcript from a real spawned-child stdout/stderr stream-error scenario showing the request rejects and the gateway does not crash.
  • Update the PR body with that proof so ClawSweeper can re-review automatically; if it does not, ask a maintainer to comment @clawsweeper re-review.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body reports focused tests and negative-control evidence, and the branch now includes a real-child test, but there is still no redacted terminal/live output in the PR body or comments showing the after-fix behavior outside test/CI evidence. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The PR body/comments still do not include redacted real behavior output from an after-fix spawned-child or live iMessage scenario; tests and CI are useful but remain supplemental for this external PR gate.

Maintainer options:

  1. Decide the mitigation before merge
    Land the narrow iMessage RPC hardening after redacted real behavior proof is attached or a maintainer explicitly overrides the proof gate; keep one-shot iMessage CLI stream hardening as separate follow-up work.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] No ClawSweeper repair lane is needed because the patch has no supported code findings; the remaining action is human/proof follow-up for the external PR gate.

Security
Cleared: Cleared: the diff only changes local child-process stream error handling and tests; it does not change dependencies, workflows, secrets, permissions, package resolution, or external code execution sources.

Review details

Best possible solution:

Land the narrow iMessage RPC hardening after redacted real behavior proof is attached or a maintainer explicitly overrides the proof gate; keep one-shot iMessage CLI stream hardening as separate follow-up work.

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

Yes, source-reproducible with high confidence: current main has stdout/stderr data handlers but no stdout/stderr error listeners, and a Node EventEmitter probe confirms unhandled error events throw. I did not run a full live imsg gateway reproduction in this read-only review.

Is this the best way to solve the issue?

Yes for the long-lived RPC client: routing process, stdin, stdout, and stderr errors through one terminal finish path is the narrow owner-boundary fix. The remaining gap is proof quality, not an alternate implementation path.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 63d71f4ab143.

Label changes

Label justifications:

  • P2: This is a focused channel reliability fix for an iMessage gateway crash class with limited blast radius and no config or API surface change.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body reports focused tests and negative-control evidence, and the branch now includes a real-child test, but there is still no redacted terminal/live output in the PR body or comments showing the after-fix behavior outside test/CI evidence. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +17, Tests +115. Total +132 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 29 12 +17
Tests 1 115 0 +115
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 144 12 +132

What I checked:

  • Repository policy read: Root AGENTS.md and the scoped extensions/AGENTS.md were read fully; plugin-boundary review, read-beyond-diff, and real-behavior-proof guidance affected this review. (AGENTS.md:1, 0d981095d430)
  • Current main lacks stdout/stderr error listeners: Current origin/main wires stdout/stderr data handlers and a child process error handler, but the only stdio stream error listener is still on stdin. (extensions/imessage/src/client.ts:102, 63d71f4ab143)
  • PR head adds terminal stream-error handling: The PR head attaches the same failFromProcessError handler to child, stdin, stdout, and stderr, then funnels close/error settlement through finish(). (extensions/imessage/src/client.ts:121, 4ffcce0f5eab)
  • Regression coverage targets the changed path: The added test emits error on stdout, stderr, and stdin, verifies pending requests reject, and adds a real spawned-child stdout destroy case. (extensions/imessage/src/client.test.ts:65, 4ffcce0f5eab)
  • Node error-event contract supports the crash class: A local EventEmitter probe threw when emitting an unhandled error event, matching the source-level risk from missing stream error listeners.
  • Related history: GitHub commit history for the same client shows the prior stdin EPIPE fix in e1a7c5b and the recent iMessage RPC stdout framing fix in 37aaa5c. (extensions/imessage/src/client.ts, e1a7c5b86030)

Likely related people:

  • amknight: Authored the merged stdin EPIPE hardening in the same iMessage RPC client via the prior fix that this PR extends to stdout/stderr. (role: introduced adjacent behavior; confidence: high; commits: e1a7c5b86030; files: extensions/imessage/src/client.ts, src/agents/mcp-stdio-transport.ts, src/process/exec.ts)
  • omarshahine: Recently merged the iMessage RPC stdout framing fix touching the same client and adjacent tests. (role: recent area contributor; confidence: high; commits: 37aaa5cc2b81; files: extensions/imessage/src/client.ts, extensions/imessage/src/status.test.ts)
  • tyler6204: CONTRIBUTING.md lists Tyler Yust for iMessage and macOS app ownership, making this a likely routing candidate for iMessage behavior. (role: listed area owner; confidence: medium; files: CONTRIBUTING.md, extensions/imessage/src/client.ts)
  • steipete: The PR is assigned to steipete, and current-main history shows recent changes around the same extension/client area. (role: recent reviewer and adjacent contributor; confidence: medium; commits: 606456394768, 4ffcce0f5eab; files: extensions/imessage/src/client.ts, extensions/imessage/src/client.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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-06T19:01:53.931Z sha 6931813 :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. 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 6, 2026
@steipete steipete self-assigned this Jul 7, 2026
@steipete

steipete commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Land-ready proof for exact head 4ffcce0f5eabc702a4bfb8aca9e455cbd346e70a:

  • Refactored child-process and stdin/stdout/stderr failures through one idempotent terminal path. It rejects all pending requests, resolves waitForClose() once, and terminates the unusable child with SIGTERM.
  • Added regression coverage for every error surface plus a real spawned Node child whose stdout is destroyed with an error; the pending request rejects, close resolves, and the child is killed.
  • Exact-head hosted CI passed: https://github.com/openclaw/openclaw/actions/runs/28836391811
  • Fresh autoreview passed with no actionable findings (confidence 0.82).
  • Targeted formatting and git diff --check passed.
  • OPENCLAW_TESTBOX=1 scripts/pr prepare-run 101084 passed the native hosted exact-head guard without changing the reviewed SHA.
  • Dependency contract checked against Node's official EventEmitter and stream error documentation: https://nodejs.org/api/events.html#error-events and https://nodejs.org/api/stream.html#event-error

Known proof gap: the real process/stream lifecycle is covered, but I did not deliberately fault a live Messages transport session.

@steipete
steipete merged commit 6522dbf into openclaw:main Jul 7, 2026
107 checks passed
@steipete

steipete commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 7, 2026
…hild (openclaw#101084)

* fix(imessage): handle stdout/stderr stream errors in the RPC client child

A dead imsg RPC helper can emit an async error on any of its stdio streams.
On a raw stream an unhandled 'error' event throws and surfaces as an
uncaughtException, crashing the gateway. openclaw#75438 added this guard for stdin
but left stdout/stderr — on the same long-lived child — unguarded.

Route stdout/stderr stream errors through the existing failAll path via a
shared failFromStreamError helper, mirroring the stdin handler. Add a
regression test that emits 'error' on each stream and asserts the child does
not throw and in-flight requests reject cleanly.

* fix(imessage): terminate failed RPC transports

* test(imessage): exercise real stream failure

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
…hild (openclaw#101084)

* fix(imessage): handle stdout/stderr stream errors in the RPC client child

A dead imsg RPC helper can emit an async error on any of its stdio streams.
On a raw stream an unhandled 'error' event throws and surfaces as an
uncaughtException, crashing the gateway. openclaw#75438 added this guard for stdin
but left stdout/stderr — on the same long-lived child — unguarded.

Route stdout/stderr stream errors through the existing failAll path via a
shared failFromStreamError helper, mirroring the stdin handler. Add a
regression test that emits 'error' on each stream and asserts the child does
not throw and in-flight requests reject cleanly.

* fix(imessage): terminate failed RPC transports

* test(imessage): exercise real stream failure

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: imessage Channel integration: imessage P2 Normal backlog priority with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants