nikivdev/code · error

failed to exec fish: {}

Error message

failed to exec fish: {}

What it means

reload_fish_shell replaces the current process with `fish -l` via Command::exec on Unix. exec only returns if it failed, so any value returned means fish could not be started, and the code bails with the OS error interpolated. On non-Unix it spawns fish instead and never errors.

Source

Thrown at src/latest.rs:70

    let result = deploy::run(DeployCommand { action: None });
    std::env::set_current_dir(prev).context("failed to restore previous directory")?;
    result
}

fn reload_fish_shell() -> Result<()> {
    if std::env::var("FISH_VERSION").is_err() {
        return Ok(());
    }
    if !atty::is(atty::Stream::Stdout) {
        return Ok(());
    }

    println!("Reloading fish shell...");
    #[cfg(unix)]
    {
        use std::os::unix::process::CommandExt;
        let err = Command::new("fish").arg("-l").exec();
        bail!("failed to exec fish: {}", err);
    }
    #[cfg(not(unix))]
    {
        let _ = Command::new("fish").arg("-l").status();
        Ok(())
    }
}

View on GitHub (pinned to a747e741ae)

Solutions

  1. Install fish (e.g. brew install fish or apt install fish) or add its directory to PATH
  2. Verify fish is runnable: `which fish` / `fish -l` in the same environment
  3. If you don't want a fish reload, run the command in an environment where the exec step is skipped (non-Unix path or alternate command)

Example fix

// before
let err = Command::new("fish").arg("-l").exec();
bail!("failed to exec fish: {}", err);
// after (check availability first)
if which::which("fish").is_err() {
    bail!("fish not found on PATH; install fish or skip reload");
}
let err = Command::new("fish").arg("-l").exec();
bail!("failed to exec fish: {}", err);
Defensive patterns

Strategy: validation

Validate before calling

fn fish_available() -> bool {
    std::process::Command::new("fish")
        .arg("-c")
        .arg("true")
        .output()
        .map(|o| o.status.success())
        .unwrap_or(false)
}
if !fish_available() { eprintln!("fish not installed/on PATH; reload skipped"); }

Type guard

fn is_unix() -> bool { cfg!(unix) }

Try / catch

match reload_fish_shell() {
    Err(e) if e.to_string().starts_with("failed to exec fish") => {
        eprintln!("fish exec failed — is fish installed and on PATH?");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling run on a Unix system when the exec of `fish -l` fails: fish is not installed or not on PATH, the binary lacks execute permission, or the exec syscall fails for another OS-level reason.

Common situations: Machine uses bash/zsh and fish was never installed; fish installed outside PATH (e.g. /opt/homebrew/bin not in PATH in a non-interactive context); minimal container images without fish.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/f3738257a502f5c8. Report an issue: GitHub.