Skip to content

fix(imessage): attach stdin error listener to prevent EPIPE gateway crash (#75438)#75608

Closed
hclsys wants to merge 1 commit intoopenclaw:mainfrom
hclsys:fix/75438-imessage-rpc-stdin-epipe
Closed

fix(imessage): attach stdin error listener to prevent EPIPE gateway crash (#75438)#75608
hclsys wants to merge 1 commit intoopenclaw:mainfrom
hclsys:fix/75438-imessage-rpc-stdin-epipe

Conversation

@hclsys
Copy link
Copy Markdown
Contributor

@hclsys hclsys commented May 1, 2026

Summary

IMessageRpcClient.request() calls this.child.stdin.write(line) with no error callback. When the iMessage RPC child closes its stdin (crash, rate limit, network hiccup), Node emits an async error on the stdin stream with code EPIPE. The existing child.on("error", ...) at line 106 does NOT catch stdin stream errors — those fire on the stream, not the child process — so the error escapes to uncaughtException and crashes the gateway.

Fix: add child.stdin.on("error", ...) listener immediately after the existing child.on("error", ...) block, routing errors through the existing failAll() helper which rejects all pending requests cleanly.

Fixes #75438.

Pre-audit

  1. Existing-helper check: failAll already exists at line 239. Reused exactly — no new helper introduced.
  2. Shared-helper caller check: failAll is private, only called within client.ts. Contract unchanged.
  3. Rival scan: no rival PRs for this specific stdin EPIPE fix.

Test plan

  • pnpm test extensions/imessage/src/client.test.ts — 1/1 pass (new test simulates EPIPE via mocked spawn, verifies pending request rejects instead of uncaughtException)
  • git diff --check — clean

…rash (openclaw#75438)

stdin write errors (e.g. EPIPE when imsg rpc process closes its stdin) are
emitted on the stdin stream, not the child process. Without an error listener
they escape to uncaughtException and kill the gateway with exit code 1.

Add child.stdin.on("error", ...) in IMessageRpcClient.start() right next to
the existing child error listener, routing stdin errors through failAll() so
pending requests receive a rejection instead of crashing the process.
@openclaw-barnacle openclaw-barnacle Bot added channel: imessage Channel integration: imessage size: S labels May 1, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

Thanks for the context here. I did a careful shell check against current main, and this is already implemented.

Close as implemented on current main. The iMessage RPC stdin EPIPE path that this PR targets is already handled in extensions/imessage/src/client.ts, and current main goes beyond this PR by adding both a stdin stream error listener and a per-write callback that rejects the affected pending request. The changelog records the fix for #75438, but no release tag contains the current proof SHA, so this appears to be fixed on main and not yet in a shipped release.

So I’m closing this as already implemented rather than keeping a duplicate issue open.

Review details

Best possible solution:

Close this PR and keep the current main implementation, which handles the iMessage stdin EPIPE failure locally in the plugin with both stream-level and per-write error handling. Any remaining work should be normal release validation for the already-landed main change, not another PR for the same behavior.

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

Yes. The reported failure path is source-visible: iMessage uses imsg rpc over child-process stdio, and current main now guards the stdin stream and write callback that would otherwise surface EPIPE asynchronously.

Is this the best way to solve the issue?

Yes for current main. The landed implementation is the narrow maintainable fix because it stays inside the iMessage RPC client and rejects pending requests rather than adding a global uncaught-EPIPE suppression.

Security review:

Security review cleared: The PR diff only touches iMessage runtime error handling, a unit test, and CHANGELOG.md, with no dependency, workflow, permission, download, publish, or secret-handling changes.

What I checked:

Likely related people:

  • steipete: Local blame/log on the iMessage client and adjacent monitor files attributes the current available history to Peter Steinberger, and prior ClawSweeper context also identified recent iMessage client/monitor maintenance by this handle. (role: recent maintainer and current proof owner; confidence: high; commits: 84c85734a813, 9314bb718084, ffe67e9cdc9e; files: extensions/imessage/src/client.ts, extensions/imessage/src/monitor/monitor-provider.ts)
  • scoootscooob: Prior related review context ties the iMessage channel move into extensions/imessage, including client.ts and monitor files, to this commit history. (role: introduced extension path; confidence: medium; commits: 0ce23dc62d37; files: extensions/imessage/src/client.ts, extensions/imessage/src/monitor/monitor-provider.ts)
  • vincentkoc: Recent adjacent iMessage monitor retry work touched the watch.subscribe lifecycle that depends on IMessageRpcClient request failure behavior. (role: adjacent maintainer; confidence: medium; commits: 35a784c16563, ea71a59127a0; files: extensions/imessage/src/monitor/monitor-provider.ts, extensions/imessage/src/monitor.watch-subscribe-retry.test.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against e0cc374b07c1; fix evidence: commit e0cc374b07c1, main fix timestamp 2026-05-01T22:38:47+01:00.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: imessage Channel integration: imessage size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IMessageRpcClient.request() does not handle async stdin write errors → uncaughtException → gateway crash

1 participant