codex-cli 0.92.0 panics on Broken pipe when stdout closes during --json streaming (macOS)

Open 💬 5 comments Opened Jan 30, 2026 by mbosley
💡 Likely answer: A maintainer (etraut-openai, contributor) responded on this thread — see the highlighted reply below.

Summary

On macOS, codex-cli 0.92.0 can crash mid-run with a Rust panic:

failed printing to stdout: Broken pipe (os error 32)

We started seeing this only after upgrading to 0.92.0. It shows up most often in headless/detached runners where codex exec --json is piped (e.g. via tee) and the stdout consumer closes.

Environment

  • codex-cli: 0.92.0
  • macOS: 15.5 (24F74)
  • Auth: API key (not ChatGPT login)

Observed error

From codex.stderr.log:

thread 'main' (...) panicked at library/std/src/io/stdio.rs:1165:9:
failed printing to stdout: Broken pipe (os error 32)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

How we trigger it

In our harness we were doing something like:

codex exec --json ... | tee events.jsonl >/dev/null

In headless/detached contexts, if the stdout consumer closes (runner exits, HUP, etc.), codex may panic with Broken pipe and terminate the run.

Minimal repro idea

This should not crash; it should exit gracefully if the consumer closes:

# Any prompt; keep it tiny to minimize cost.
codex exec --skip-git-repo-check --json "Print OK" | head -n 1 >/dev/null

(If head closes early, upstream should handle EPIPE without panicking.)

Workarounds

  • Redirect stdout directly to a file instead of piping:
codex exec --json ... > events.jsonl 2> codex.stderr.log
  • Pinning to codex-cli 0.91.0 avoids the issue for us in headless runs.

Requested behavior

Please handle EPIPE/BrokenPipe on stdout gracefully (no panic) when streaming --json.

Happy to provide more logs or try a debug build/backtrace if you point me at what to collect.

View original on GitHub ↗

5 Comments

mbosley · 6 months ago

Additional datapoint: in our environment, redirecting stdout to a file (avoiding | tee) improved things but did not fully eliminate mid-run failures in headless execution. The only change that made headless runs consistently reliable for us was pinning to codex-cli 0.91.0 (running the pinned CLI in parallel and using it for headless runs).

So: stdout EPIPE handling seems like one culprit, but there may be another regression in 0.92.0 affecting long/headless runs. Happy to run any additional diagnostics or try specific flags/builds if useful.

etraut-openai contributor · 6 months ago

Thanks for the bug report. I think I understand the root cause, but it's a long-standing issue. I'm not 100% sure why you saw this first in 0.92. I have a theory that a recently-introduced warning may have exacerbated the problem. Do you happen to have any feature flags enabled in your config.toml that correspond to "under-development features"? If you launch codex in normal interactive (TUI) mode, do you see a warning printed?

mbosley · 6 months ago

Checked feature flags + quick experiment:

  • My ~/.codex/config.toml has both under-development flags enabled:
  • [features] unified_exec = true
  • [features] shell_snapshot = true
  • Disabling both via CLI overrides did not change the broken-pipe panic when stdout is closed early. Repro still panics on 0.92.0:
  • codex exec --json "echo OK" | head -n 1
  • codex --config "features.unified_exec=false" --config "features.shell_snapshot=false" exec --json "echo OK" | head -n 1

Both runs exit rc=0 but print the same panic to stderr (failed printing to stdout: Broken pipe).

Also: in non-interactive codex exec runs I don’t see any warning printed to stderr at startup (stderr is empty unless an error/panic occurs). Happy to run additional probes if you have a preferred build/flag combo to try.

etraut-openai contributor · 6 months ago

And just to confirm, when you downgrade to 0.91.0, the problem goes away? I just want to verify that it's a Codex regression rather than some other recent change in your environment or configuration.

Iloveshe · 3 months ago

I can still reproduce this on a newer macOS release build.

Environment:

  • macOS 26.4.1
  • arm64 / Apple Silicon
  • codex-cli 0.130.0

Minimal repro:

RUST_BACKTRACE=1 codex exec --ignore-user-config --disable plugins --skip-git-repo-check --json "Print OK" | head -n 1

Observed output:

{"type":"thread.started","thread_id":"019e4989-2db5-7ef1-88fd-480335f84568"}

thread 'main' (59953825) panicked at library/std/src/io/stdio.rs:1165:9:
failed printing to stdout: Broken pipe (os error 32)
stack backtrace:
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

I noticed this issue already has a linked fix commit and PR (#10259), but the current 0.130.0 npm release I have installed still panics in this path. The repro above also uses --ignore-user-config --disable plugins, so it does not appear to depend on plugin initialization.

For reference, current main still shows the JSONL path writing through println! in codex-rs/exec/src/event_processor_with_jsonl_output.rs, EventProcessorWithJsonOutput::emit, lines 103-115 in the GitHub view I checked. That still looks like the place where an early downstream close from head can turn EPIPE into a Rust stdout panic instead of a graceful shutdown.