nikivdev/code · error
fish shell required. Run: chsh -s {}
Error message
fish shell required. Run:
chsh -s {} What it means
`ensure_fish_shell` is a health/startup check that reads the `SHELL` environment variable and requires it to contain "fish". If not, it locates the fish binary with `which` and bails telling the user to switch their login shell via `chsh -s <path>`. The check verifies the user's configured login shell, not merely that fish exists.
Source
Thrown at src/health.rs:84
println!(
"ℹ️ run internal repo not detected at {}",
run_internal.display()
);
}
println!(
"ℹ️ run shortcuts: f r <task>, f ri <task>, f rp <project> <task>, f rip <project> <task>"
);
Ok(())
}
fn ensure_fish_shell() -> Result<()> {
let shell = env::var("SHELL").unwrap_or_default();
if !shell.contains("fish") {
let fish = which::which("fish")
.context("fish is required; install it and ensure it is on PATH")?;
bail!("fish shell required. Run:\n chsh -s {}", fish.display());
}
Ok(())
}
fn ensure_fish_flow_init() -> Result<()> {
if which::which("f").is_ok() {
return Ok(());
}
let config_path = fish_config_path()?;
let content = fs::read_to_string(&config_path).unwrap_or_default();
if content.contains("# flow:start") {
return Ok(());
}
println!(
"⚠ flow fish integration missing in {}. Ensure the `f` binary is on PATH, then run: f shell-init fish",
config_path.display()View on GitHub (pinned to a747e741ae)
Solutions
- Change your login shell to fish as the message suggests: `chsh -s $(which fish)` (then re-login)
- For a one-off run, set the variable: `SHELL=$(which fish) f <command>`
- Verify the variable: `echo $SHELL` — it must point at a path containing "fish"
- If the binary path itself doesn't contain the substring 'fish' (custom install path), symlink or reinstall fish to a standard path like /usr/bin/fish
Example fix
# before echo $SHELL # /bin/bash # after chsh -s /usr/bin/fish # re-login, then: echo $SHELL # /usr/bin/fish
Defensive patterns
Strategy: validation
Validate before calling
let shell = std::env::var("SHELL").unwrap_or_default();
if !shell.contains("fish") {
eprintln!("this tool requires fish as your login shell; run: chsh -s $(which fish)");
std::process::exit(1);
} Type guard
fn is_fish_shell() -> bool {
std::env::var("SHELL")
.map(|s| s.contains("fish"))
.unwrap_or(false)
} Try / catch
match ensure_fish_shell() {
Err(e) if e.to_string().contains("fish shell required") => {
eprintln!("{e}");
eprintln!("or run once with: SHELL=$(which fish) f <cmd>");
}
r => r?,
} Prevention
- Run `chsh -s $(which fish)` right after installing fish, then re-login
- Set SHELL explicitly in scripts/CI that invoke the tool
- Check `echo $SHELL` before running the tool in unfamiliar environments
- Prefer running the tool from an interactive fish session
When it happens
Trigger: Running the tool with `$SHELL` set to bash/zsh/sh (or unset, defaulting to empty string) even though fish is installed.
Common situations: Running from a non-interactive context (IDE terminal, cron, CI) where SHELL is inherited as /bin/bash; fresh machines where fish was installed but `chsh` was never run; SSH sessions with a different default shell; calling the tool via `bash -c` from a script.
Related errors
- could not resolve commit report directory
- OPENROUTER_API_KEY not set. Get one at https://openrouter.ai
- missing CLOUDFLARE_API_TOKEN; set it in shell env or Flow pe
- missing CLOUDFLARE_ACCOUNT_ID; set it in shell env or Flow p
- Missing GEMINI_API_KEY/GOOGLE_API_KEY (set env var or add to
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/dea0fce0a0ae4faf.
Report an issue: GitHub.