Hmbown/CodeWhale · error · io::Error

git not found on PATH

Error message

git not found on PATH

What it means

commit_tree_preserving_date in the snapshot repo module shells out to git via crate::dependencies::Git::command(), which resolves the git executable on PATH. When no git binary is found it returns an io::Error of kind NotFound with this message. The snapshot subsystem needs git for commit-tree plumbing, so without it snapshot rebuilds cannot proceed.

Solutions

  1. Install git (e.g. `apt install git`, `brew install git`) so it resolves on PATH.
  2. Relaunch the app from a shell with a normal PATH, or add git's directory to PATH in the launch environment.
  3. If git lives in a nonstandard location, prepend its directory: PATH=/opt/git/bin:$PATH codewhale.
  4. In code, surface a clear user-facing setup hint when Git::command() returns None instead of a bare NotFound io error.

Example fix

// before
codewhale  # launched from GUI, PATH=/usr/local/bin:/usr/bin (no git installed)
// after
sudo apt-get install -y git && codewhale
Defensive patterns

Strategy: fallback

Validate before calling

// shell, before launching
which git || { echo "git required on PATH"; exit 1; }

Try / catch

// rust, around snapshot rebuild
match commit_tree_preserving_date(&args, ts) {
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
        eprintln!("git is not installed or not on PATH; snapshot rebuild skipped: {e}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling rebuild_survivor_chain -> commit_tree_preserving_date when the git executable is absent from PATH at the moment the TUI process runs (Git::command() returns None).

Common situations: TUI launched from a desktop launcher or systemd unit with a minimal PATH that excludes /usr/bin; running inside a slim Docker image or CI container without git installed; broken PATH after shell config changes.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/cd8c22e95158fa72. Report an issue: GitHub.

Appendix: source

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

                &["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 73e0f67d83)