macOS app: default exec_command resolves /bin/zsh as relative bin/zsh when login shell is fish
What version of the Codex App are you using (From “About Codex” dialog)?
- ChatGPT desktop app: 26.810.52044 (build 6662)
- Bundled Codex CLI:
codex-cli 0.148.0-alpha.9 - Standalone Codex CLI:
codex-cli 0.147.0
What subscription do you have?
Logged in using ChatGPT. The exact subscription tier is not exposed in the local agent environment.
What platform is your computer?
Darwin 25.5.0 arm64 arm
macOS 26.5.2 (build 25F84)
Apple Silicon
Login shell:
SHELL=/opt/homebrew/bin/fish
fish, version 4.8.1
What issue are you seeing?
The first local shell tool call commonly omits the optional shell parameter. In this environment that call fails before the requested command starts:
sandbox-exec: execvp() of 'bin/zsh' failed: No such file or directory
The important detail is that the failing executable is the relative path bin/zsh, not the valid absolute path /bin/zsh.
Retrying the same command with either of these explicit settings succeeds:
shell: "/bin/zsh"
login: false
shell: "/opt/homebrew/bin/fish"
login: false
This makes the problem appear to happen only on the initial/default shell call: after the failure, the agent can recover by explicitly selecting an absolute shell path.
What steps can reproduce the bug?
- On macOS, configure the login shell as Homebrew fish:
/opt/homebrew/bin/fish. - Start a local Codex/ChatGPT desktop thread.
- Have the agent invoke
exec_commandfor a trivial command such aspwd, omitting the optionalshellfield. - Observe:
``text``
sandbox-exec: execvp() of 'bin/zsh' failed: No such file or directory
- Retry the same command with
shell: "/bin/zsh"andlogin: false. - Observe that the command succeeds.
The behavior was reproduced with simple commands and is independent of the workspace command itself.
What is the expected behavior?
When the shell parameter is omitted, the app should resolve the default/fallback shell to a valid absolute executable path and preserve the leading slash when launching it.
For an unsupported login shell such as fish, the existing macOS fallback to zsh should launch /bin/zsh, not bin/zsh.
Additional information
The public shell detection code currently declares the macOS zsh fallback as the absolute path /bin/zsh and falls back to zsh when the user's shell type is unsupported:
- https://github.com/openai/codex/blob/main/codex-rs/shell-command/src/shell_detect.rs#L166
- https://github.com/openai/codex/blob/main/codex-rs/shell-command/src/shell_detect.rs#L275-L286
This suggests the leading slash may be lost after shell detection, possibly at an app/unified-exec process boundary.
Related issues, but with materially different reproduction:
- #37594 and #20770: explicit shell paths also fail and all exec calls are blocked.
- #3916: the user's default shell is not respected, but it does not report the relative
bin/zshlaunch failure.
Current workaround: instruct the agent to always pass an absolute shell path and login: false.
No session transcript or app logs are attached because they may contain private workspace data.
1 Comment
I traced this against current public source at
711a5f8b3a6eb40134146ae9ec22fdcdda5e3170and found the failure occurs earlier than the unified-exec / Seatbelt boundary.Root cause
which::which("zsh")can itself return a relative path such asbin/zshwhenPATHcontains a relative entry. Codex accepts that lookup result before reaching the absolute/bin/zshfallback. The later unified-exec, Seatbelt, andexecvplayers preserve the already-relative value; they are not stripping the leading slash.Narrow repair I validated locally
When the lookup result is relative, anchor it to the shell-detection-time current working directory. Leave already-absolute lookup results unchanged. I intentionally did not canonicalize the result, because that changes symlink-sensitive
..path identity.I captured two fail-before regressions:
PATHentry -> detected shell path becomesbin/zsh;..identity.With the narrow anchoring repair, both regressions pass.
Validation on the repaired public source:
codex-shell-command: 150/150 passcodex-coretests: 4/4 passSo the smallest supported fix appears to be in
codex-rs/shell-command/src/shell_detect.rs: normalize only relative lookup results against the detection-time CWD, rather than changing later execution layers or the absolute fallback behavior.AI-assisted investigation and test construction; I reviewed the root cause, repair boundary, and validation results.