Shell tool execution breaks when snapshot prelude is shell-incompatible (zsh snapshot sourced under bash), causing preamble-without-execution behavior

Open 💬 3 comments Opened Feb 6, 2026 by archiboi69
💡 Likely answer: A maintainer (jif-oai, contributor) responded on this thread — see the highlighted reply below.

Summary

Codex Desktop/CLI can fail to execute shell tool commands when runtime prepends source ~/.codex/shell_snapshots/<id>.sh and that snapshot contains syntax incompatible with the actual runtime shell (bash -lc). The command itself never runs because snapshot sourcing fails first.

Environment

  • Codex: 0.98.0 (CLI + Desktop bundle)
  • OS: macOS Sequoia (arm64)
  • User shell: zsh 5.9
  • Runtime wrapper observed: bash -lc

Observed behavior

  • Assistant says it will run a shell command (preamble visible).
  • No expected command output appears.
  • Underlying failure occurs before command execution due to snapshot parse errors.

Concrete evidence

Running:

rg -n "gpt-5\.3|tool.?call|shell|dispatch|stream|adapter|ToolCall|function.?call|unified_exec" /path/to/codex

failed with:

~/.codex/shell_snapshots/<snapshot-id>.sh: line 620: syntax error near unexpected token `('
... local -a packages_full_path=(${global_node_modules}/*(N))
... builtin: autoload: not a shell builtin
... syntax error near unexpected token `}'

This is zsh syntax being sourced in bash.

After deleting ~/.codex/shell_snapshots, shell tool worked immediately:

  • echo TOOL_OK && date → success, exit 0
  • same rg command → success, exit 0

Expected behavior

  • Tool calls should not be blocked by incompatible snapshot prelude.
  • If snapshot sourcing fails, Codex should either:
  • skip snapshot and run command in clean mode, or
  • fail loudly with explicit tool-call error surfaced in UI/logs.

Actual behavior

  • Snapshot prelude failure prevents command execution.
  • UX appears as assistant no-op / “preamble without execution.”

Likely root cause

  • Snapshot generation shell and execution shell can differ.
  • Runtime rewrite unconditionally sources snapshot before command.
  • Failure handling allows opaque no-op experience.

Minimal repro

  1. Ensure shell snapshots are enabled and a zsh-derived snapshot exists in ~/.codex/shell_snapshots/.
  2. Execute a shell tool command that runs via bash -lc.
  3. Observe parse errors in snapshot file and no command execution.

Fix direction

  • Record snapshot shell type and source only when runtime shell matches.
  • Add fallback: if snapshot source fails, continue without snapshot (or guarded by strict mode).
  • Surface explicit ToolCall failure event when prelude fails.
  • Add regression test: zsh snapshot + bash runtime must not silently block commands.

Impact

  • Breaks trust in agent execution (assistant claims action, command doesn’t run).
  • Causes intermittent-looking failures tied to snapshot/session state.
  • Blocks reliable terminal workflows.

View original on GitHub ↗

3 Comments

archiboi69 · 6 months ago

Found root cause: Codex Desktop enables shell snapshot via Statsig feature overrides (runtime/session flags), which override [config.toml].

Evidence: Desktop log shows at startup:
Features enabled: enable_request_compression, collaboration_modes, personality, request_rule, shell_snapshot.

App Local Storage LevelDB contains Statsig feature_overrides with shell_snapshot: true.

Core only snapshots when Feature::ShellSnapshot is enabled ([codex.rs (line 1015)] feature key in [features.rs]

Config layering precedence shows session flags above user config ([README.md].

jif-oai contributor · 6 months ago

Will fix thanks

archiboi69 · 6 months ago
Will fix thanks

slay