Hmbown/CodeWhale · error · std::io::Error

git not found on PATH

Error message

git not found on PATH

What it means

NotFound error raised when crate::dependencies::Git::command() cannot resolve the git executable on PATH and the snapshot repo then needs to run commit-tree (commit_tree_preserving_date, used during history rebuild/prune to keep survivor commits' original dates). Every snapshot git invocation goes through this dependency shim, so a missing git binary disables snapshots entirely.

Source

Thrown at crates/tui/src/snapshot/repo.rs:794

                &["update-ref", "HEAD", &final_sha],
            )?;
            if !up.status.success() {
                return Err(io_other(format!(
                    "update-ref HEAD failed: {}",
                    String::from_utf8_lossy(&up.stderr).trim()
                )));
            }
        }
        Ok(())
    }

    /// Run a `commit-tree` invocation with the author/committer dates pinned
    /// to `timestamp` (Unix seconds), so a rebuilt survivor keeps its real
    /// age instead of stamping "now".
    fn commit_tree_preserving_date(&self, args: &[&str], timestamp: i64) -> io::Result<String> {
        let date = format!("{timestamp} +0000");
        let out = crate::dependencies::Git::command()
            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "git not found on PATH"))?
            .arg("--git-dir")
            .arg(&self.git_dir)
            .arg("--work-tree")
            .arg(&self.work_tree)
            .env("GIT_AUTHOR_DATE", &date)
            .env("GIT_COMMITTER_DATE", &date)
            .args(args)
            .output()?;
        if !out.status.success() {
            return Err(io_other(format!(
                "commit-tree failed: {}",
                String::from_utf8_lossy(&out.stderr).trim()
            )));
        }
        Ok(String::from_utf8_lossy(&out.stdout).trim().to_string())
    }

    /// Keep only the latest `max_count` snapshots, dropping older ones.

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Install git and confirm `git --version` works in the same environment the app runs in
  2. If launching from a GUI, start the app from a login shell or configure the launcher to inherit a PATH that includes git (/usr/bin, /opt/homebrew/bin, ~/.nix-profile/bin)
  3. In containers/images, add git to the image rather than relying on runtime mounting

Example fix

# before
$ open -a Codewhale        # PATH=/usr/bin:/bin:/usr/sbin:/sbin -> Err: git not found on PATH

# after
$ /opt/homebrew/bin/git --version   # verify location
$ codewhale                        # launched from login shell with git on PATH
Defensive patterns

Strategy: validation

Validate before calling

// Verify git is resolvable in the app's own environment before enabling snapshots.
if which::which("git").is_err() {
    eprintln!("snapshots require git on PATH");
    std::process::exit(2);
}

Type guard

fn is_git_missing(e: &std::io::Error) -> bool {
    e.kind() == std::io::ErrorKind::NotFound && e.to_string().contains("git")
}

Try / catch

match snapshots::Repo::open(&ws) {
    Ok(r) => Ok(r),
    Err(e) if is_git_missing(&e) => disable_snapshots_with_notice("install git and restart"),
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Snapshot pruning/rebuild runs commit-tree while the git executable is not resolvable from the process PATH — git not installed, or the app launched from an environment whose PATH lacks git (GUI launchers, service contexts, minimal containers).

Common situations: macOS launch from Finder/Dock where PATH is the minimal system default; systemd/service or cron launches with sanitized env; distrobox/Nix shells without git in scope; slim Docker images without git installed.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/cd8c22e95158fa72. Report an issue: GitHub.