openai/codex · error · anyhow::Error

zsh fork feature enabled, but packaged zsh fork `{}` is not

Error message

zsh fork feature enabled, but packaged zsh fork `{}` is not usable

What it means

Codex fails during session construction (session.rs) when the experimental zsh fork shell feature (Feature::ShellZshFork) is enabled in config.features. The code first requires config.zsh_path to be Some (a separate error covers the None case), then checks zsh_path.is_file(); if the packaged zsh binary is missing it falls back to shell::get_shell(ShellType::Zsh), which searches the system for zsh. This error means BOTH failed: the packaged zsh fork at the printed path is not a usable file AND no system zsh could be located. The session cannot start until the shell is resolvable.

Source

Thrown at codex-rs/core/src/session/session.rs:1158

            let use_zsh_fork_shell = config.features.enabled(Feature::ShellZshFork);
            let default_shell = if let Some(user_shell_override) =
                session_configuration.user_shell_override.clone()
            {
                user_shell_override
            } else if use_zsh_fork_shell {
                let zsh_path = config.zsh_path.as_ref().ok_or_else(|| {
                    anyhow::anyhow!(
                        "zsh fork feature enabled, but no packaged zsh fork is available for this install"
                    )
                })?;
                if zsh_path.is_file() {
                    shell::Shell {
                        shell_type: shell::ShellType::Zsh,
                        shell_path: zsh_path.clone(),
                    }
                } else {
                    shell::get_shell(shell::ShellType::Zsh).ok_or_else(|| {
                        anyhow::anyhow!(
                            "zsh fork feature enabled, but packaged zsh fork `{}` is not usable",
                            zsh_path.display()
                        )
                    })?
                }
            } else {
                shell::default_user_shell()
            };
            let use_executor_shell_snapshots = config.features.enabled(Feature::ShellSnapshotV2)
                && config.features.enabled(Feature::ShellTool)
                && config.features.enabled(Feature::UnifiedExec)
                && matches!(
                    codex_tools::UnifiedExecShellMode::for_session(
                        config.features.get(),
                        crate::tools::tool_user_shell_type(&default_shell),
                        config.zsh_path.as_ref(),
                        config.main_execve_wrapper_exe.as_ref(),
                    ),

View on GitHub (pinned to 339751715c)

Solutions

  1. Check the exact path printed in the error (ls -l <path>) and reinstall or update the Codex install so the packaged zsh fork exists there
  2. If the file exists, fix usability: chmod +x it, and on macOS run xattr -d com.apple.quarantine <path>
  3. Install a system zsh (brew install zsh / apt install zsh) so the get_shell(ShellType::Zsh) fallback succeeds
  4. If neither is possible, disable the feature by removing the zsh fork flag from features config so the default user shell is used

Example fix

// config.toml — before
[features]
shell_zsh_fork = true

// after (no packaged/system zsh available)
[features]
# shell_zsh_fork = true  // disabled; fall back to default_user_shell()
Defensive patterns

Strategy: validation

Validate before calling

// Run before session construction / before enabling the zsh fork feature
fn zsh_fork_ready(cfg_zsh_path: Option<&std::path::Path>) -> bool {
    match cfg_zsh_path {
        Some(p) if p.is_file() => true,
        _ => codex_core::shell::get_shell(codex_core::shell::ShellType::Zsh).is_some(),
    }
}

Type guard

fn usable_zsh_available(zsh_path: Option<&std::path::Path>) -> bool {
    zsh_path.is_some_and(|p| p.is_file())
        || codex_core::shell::get_shell(codex_core::shell::ShellType::Zsh).is_some()
}

Try / catch

// Session construction returns anyhow::Result — surface it, don't unwrap:
match Session::new(config).await {
    Err(e) if e.to_string().contains("zsh fork") => { /* disable feature or guide install */ }
    other => other?,
}

Prevention

When it happens

Trigger: Enabling the zsh fork feature flag in config (e.g. [features] shell_zsh_fork) while (a) the install's packaged zsh fork binary at config.zsh_path has been deleted, moved, corrupted, or never downloaded, AND (b) no zsh exists on PATH so get_shell(ShellType::Zsh) returns None.

Common situations: Partial or interrupted install/update that dropped the bundled zsh fork; custom CODEX_HOME pointing at a directory that lacks the zsh payload; dev builds that never bundle zsh; macOS quarantine (com.apple.quarantine) or missing execute bit making the file unusable; sandboxed/scrubbed environments where PATH has no zsh.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/2efafe728326c2e7. Report an issue: GitHub.