codex exec exits 0 even when command_execution fails with nonzero exit code

Open 💬 2 comments Opened Mar 23, 2026 by aquiles-ai123

codex exec exits 0 even when the requested command fails and the JSON transcript marks it failed

Summary

When codex exec is used non-interactively to run a prompt that executes a failing shell command, the command failure is correctly recorded inside the transcript, but the outer codex exec process still exits with code 0.

This makes it hard to use codex exec safely in automation, because a failing tool command is not reflected in the CLI process exit status.

Repro

Plain output mode:

codex exec --ephemeral --skip-git-repo-check --color never -C /home/cryptotrading74   "Run exactly: false and stop."
printf "outer_exit=%s
" "$?"

Observed output excerpt:

exec
/bin/bash -lc false in /home/cryptotrading74 exited 1 in 0ms:

codex
Ran `false`. It exited with status `1`.

outer_exit=0

JSON mode:

codex exec --ephemeral --skip-git-repo-check --color never --json -C /home/cryptotrading74   "Run exactly: false and stop."   > /tmp/codex_false_exit.jsonl
printf "outer_exit=%s
" "$?"

Observed transcript excerpt:

{"type":"item.completed","item":{"id":"item_1","type":"command_execution","command":"/bin/bash -lc false","exit_code":1,"status":"failed"}}

Observed shell exit:

outer_exit=0

Expected behavior

If the requested command fails and the task ends in that failed state, codex exec should return a nonzero exit code, or provide a documented flag that enables failure-propagating exit behavior.

Actual behavior

The nested command fails, the transcript marks it as failed, but codex exec itself returns 0.

Why this matters

This makes CI and scripting brittle because callers cannot rely on the process exit status to detect command failure.

For comparison, true CLI parse errors do propagate a nonzero exit code correctly. For example:

printf '' | codex exec --ephemeral --skip-git-repo-check --color never -C /home/cryptotrading74 - false
printf "outer_exit=%s\n" "$?"

returns:

error: unexpected argument 'false' found
...
outer_exit=2

So the CLI already uses nonzero exits for real invocation failures, but a nested command_execution failure inside exec still yields outer exit 0.

Files / artifacts

  • /tmp/codex_false_exit.jsonl
  • /tmp/codex_false_exit_repro2.jsonl

Suggested title

codex exec exits 0 even when command_execution fails with nonzero exit code

View original on GitHub ↗

2 Comments

raye-deng · 5 months ago

This is a significant issue for anyone building CI pipelines around codex exec. Silent success on actual failure is one of the hardest failure modes to debug, because everything downstream assumes the step passed.

We see the same class of problem — "all gates pass, but something is actually broken" — show up frequently in AI-assisted development pipelines. A few patterns we have observed:

  1. Exit code masking (exactly this issue): the orchestrator reports success while the inner tool recorded a failure. The transcript has the truth, but the pipeline acts on the exit code.
  1. Compilation success hiding runtime failures: AI-generated imports reference packages that type-check correctly (because the type definitions exist or are inferred) but the actual package does not exist on the registry. Build passes, runtime crashes.
  1. Test success hiding production failures: AI-generated code passes the existing test suite because the tests were written for the old behavior. The new code introduces subtle regressions that only manifest in paths not covered by tests.

The common thread is that the standard success signal (exit code, compilation, test pass) does not reflect the actual state of the code. Each of these requires a different verification strategy — exit code propagation for orchestrators, registry validation for imports, behavioral diffing for test coverage gaps.

We have been building deterministic checks for cases 2 and 3 as a CI gate: npx @opencodereview/cli scan . --sla L1 — catches phantom imports and deprecated API usage that pass all other gates.

middleDuckAi · 5 months ago

Repro

  • Reproduced this on current main.
  • codex exec was exiting 0 even when the nested shell command finished with a non-zero status.

Root Cause

  • run_exec_session only flipped error_seen on abort or server-error paths, but did not mark the rollout as failed when it received ExecCommandEnd for the active task with Failed or Declined status.
  • I prepared a narrow local patch in exec/src/lib.rs that marks error_seen on matching ExecCommandEnd failure or decline and added a regression test in failed_command_exit.rs proving that a false command returns exit code 1.

Validation

  • CARGO_TARGET_DIR=/tmp/codex-target-15536 cargo test -p codex-exec exits_non_zero_when_shell_command_finishes_failed -- --nocapture
  • just fix -p codex-exec
  • CARGO_TARGET_DIR=/tmp/codex-target-15536 cargo test -p codex-exec

Risk

  • Low. The change is scoped to propagation of the active command failure state and does not broaden exec behavior beyond that contract.

Maintainer Pickup

gh pr create --repo openai/codex --base main --head middleDuckAi:middleDuck/codex-15536-codex-exec-exits-0-even-when --title "$(gh pr view 7 --repo middleDuckAi/codex --json title --jq .title)" --body "$(gh pr view 7 --repo middleDuckAi/codex --json body --jq .body)"