Skip to content

fix(codex): prevent uncaught exceptions from sandbox subprocess stream errors#102326

Closed
zw-xysk wants to merge 1 commit into
openclaw:mainfrom
zw-xysk:fix/codex-sandbox-stream-errors
Closed

fix(codex): prevent uncaught exceptions from sandbox subprocess stream errors#102326
zw-xysk wants to merge 1 commit into
openclaw:mainfrom
zw-xysk:fix/codex-sandbox-stream-errors

Conversation

@zw-xysk

@zw-xysk zw-xysk commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Three Codex modules spawn child processes and register stdout/stderr data listeners but omit error handlers on the streams themselves. When a child process pipe emits an error — a real risk when a sandbox process crashes (EPIPE), is killed during timeouts, or its stream is destroyed during teardown — the missing listener causes an uncaught exception that terminates the entire Node.js process, taking down the Codex sandbox and all active code execution with it.

The existing child.on("error") handlers in all three files only catch spawn-level failures (ENOENT when the binary is missing, etc.). They do not cover stream errors on stdout/stderr, because in Node.js these are independent Readable streams with their own event dispatch.

Affected locations:

File stdout data stderr data stdout error stderr error child error
sandbox-exec-server/processes.ts ✅ (spawn only)
sandbox-exec-server/http.ts ✅ (spawn only)
node-cli-sessions.ts ✅ (spawn only)

Changes

extensions/codex/src/app-server/sandbox-exec-server/processes.ts (+6):

  • Add child.stdout.on("error", handler) logging via embeddedAgentLog.warn()
  • Add child.stderr.on("error", handler) logging via embeddedAgentLog.warn()

extensions/codex/src/app-server/sandbox-exec-server/http.ts (+6):

  • Add params.child.stdout.on("error", handler) logging via embeddedAgentLog.warn()
  • Add params.child.stderr.on("error", handler) logging via embeddedAgentLog.warn()

extensions/codex/src/node-cli-sessions.ts (+4):

  • Add child.stdout.on("error", () => {}) — stream errors are benign; the process-level error handler already rejects the promise
  • Add child.stderr.on("error", () => {}) — same

Evidence

Unit tests (29/29 passed, 3 test files):

 Test Files  3 passed (3)
      Tests  29 passed (29)

Real behavior proof (platinum):

[+0.019s][LIN-66D8BD4EA2C:1077430] stdout error handler fired: Error: EPIPE: stdout stream broken
[+0.219s][LIN-66D8BD4EA2C:1077430] stdout stream error caught without crash: ✓

[+0.226s][LIN-66D8BD4EA2C:1077430] stderr error handler fired: Error: EPIPE: stderr stream broken
[+0.427s][LIN-66D8BD4EA2C:1077430] stderr stream error caught without crash: ✓

[+0.428s][LIN-66D8BD4EA2C:1077430]   🐚 RESULT: PASS (platinum)
[+0.428s][LIN-66D8BD4EA2C:1077430]   Both stdout and stderr stream errors are handled without crashing.

Proof method: spawned real Node.js child processes with piped stdout/stderr, forcibly destroyed each stream to simulate EPIPE, and verified both stdout and stderr error handlers fire without crashing the process.

Review

  • Manually reviewed and verified
  • AI-assisted: Yes

…m errors

Three Codex modules spawn child processes and register stdout/stderr
data listeners but omit error handlers. When a child process pipe emits
an error (EPIPE during process crash, destroyed stream during teardown),
the missing listener causes an uncaught exception that terminates the
entire Node.js process — taking down the Codex sandbox and all active
code execution.

Add stdout/stderr error handlers in all three locations:

- sandbox-exec-server/processes.ts: log via embeddedAgentLog.warn()
- sandbox-exec-server/http.ts: log via embeddedAgentLog.warn()
- node-cli-sessions.ts: ignore (matching src/process/exec.ts pattern,
  process-level error handler already rejects the promise)

All three children already have child.on('error') for spawn-level failures
(ENOENT, etc.), which does NOT cover independent stream errors on the
stdout/stderr Readable streams.
@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close: this PR should not stay as a third landing candidate because two existing open, proof-positive PRs already cover the same Codex stream-error work, and this branch handles the Codex CLI resume path less safely than the existing focused fix.

Canonical path: Close this combined branch and proceed with the two existing narrower, proof-positive PRs: one for sandbox process/HTTP stream errors and one for Codex CLI resume lifecycle errors.

So I’m closing this here because the remaining work is already tracked in the canonical issue.

Review details

Best possible solution:

Close this combined branch and proceed with the two existing narrower, proof-positive PRs: one for sandbox process/HTTP stream errors and one for Codex CLI resume lifecycle errors.

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

Yes, from source inspection and Node's EventEmitter contract: current main attaches stdout/stderr data handlers without stream error listeners, so an emitted stream error is unhandled. I did not run a failing current-main reproduction in this read-only review.

Is this the best way to solve the issue?

No. The sandbox listener part is already covered by #101777, and the resume path should use the stronger terminate, wait, and report shape in #102127 rather than swallowing stream errors.

Security review:

Security review cleared: Cleared: the diff adds child-process stream listeners/logging only and does not change dependencies, workflows, permissions, secrets, package metadata, or install scripts.

AGENTS.md: found and applied where relevant.

What I checked:

Likely related people:

  • joshavant: Verified GitHub commit history shows Josh Avant authored the Codex sandbox execution hardening that introduced the sandbox exec-server process and HTTP modules touched by this PR. (role: feature introducer; confidence: high; commits: ba06376c7955; files: extensions/codex/src/app-server/sandbox-exec-server/processes.ts, extensions/codex/src/app-server/sandbox-exec-server/http.ts, extensions/codex/src/app-server/sandbox-exec-server.ts)
  • mbelinky: Verified GitHub commit history shows Mariano Belinky authored the Codex CLI node-session binding that introduced node-cli-sessions.ts and its resume command surface. (role: feature introducer; confidence: high; commits: 27c9564081f5; files: extensions/codex/src/node-cli-sessions.ts, extensions/codex/src/node-cli-sessions.test.ts, extensions/codex/src/conversation-binding.ts)
  • llagy009: Verified GitHub commit history shows llagy009 recently changed node-cli-sessions.ts and its tests for Codex CLI session preview behavior. (role: recent area contributor; confidence: medium; commits: 52e2b003e63d; files: extensions/codex/src/node-cli-sessions.ts, extensions/codex/src/node-cli-sessions.test.ts)
  • Agustin Rivera: Verified GitHub commit history shows Agustin Rivera recently modified the sandbox HTTP request helper and its tests, which overlap the streaming HTTP helper touched here. (role: recent area contributor; confidence: medium; commits: 21410d1c3247; files: extensions/codex/src/app-server/sandbox-exec-server/http.ts, extensions/codex/src/app-server/sandbox-exec-server.http.test.ts)

Codex review notes: model internal, reasoning high; reviewed against 6630138598b3.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jul 9, 2026
@clawsweeper clawsweeper Bot closed this Jul 9, 2026
@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🦞✅
ClawSweeper autoclose is complete.

Reason: structured ClawSweeper close marker: close-required (sha=6b31a94e08237a9223a266df7c935c72b9a29785)

Closed:

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

Labels

extensions: codex merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant