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

git not found

Error message

git not found

What it means

NotFound ('git not found') raised inside the tasks tool when it spawns `git apply --check` to validate an attempt's patch artifact and crate::dependencies::Git::command() cannot find git on PATH. The check runs on a spawn_blocking thread with the workspace as current_dir; the PATH lookup is inherited from the app process, so the workspace's own git config is irrelevant — only the executable's presence matters.

Source

Thrown at crates/tui/src/tools/tasks.rs:831

            .task_manager
            .as_ref()
            .ok_or_else(|| ToolError::not_available("TaskManager is not attached"))?;
        let task = read_task_for_input(input, context).await?;
        let attempt_id = required_str(input, "attempt_id")?;
        let attempt = task
            .attempts
            .iter()
            .find(|attempt| attempt.id == attempt_id)
            .ok_or_else(|| ToolError::invalid_input(format!("Attempt not found: {attempt_id}")))?;
        let patch_ref = attempt
            .patch_path
            .as_ref()
            .ok_or_else(|| ToolError::invalid_input("Attempt has no patch artifact"))?;
        let patch_path = manager.artifact_absolute_path(patch_ref);
        let workspace = context.workspace.clone();
        let out = tokio::task::spawn_blocking(move || {
            crate::dependencies::Git::command()
                .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, "git not found"))?
                .args(["apply", "--check"])
                .arg(&patch_path)
                .current_dir(&workspace)
                .output()
        })
        .await
        .map_err(|join_err| {
            // Surface the otherwise-discarded join error for debugging; the
            // returned ToolError (and thus user-facing behavior) is unchanged.
            tracing::debug!(error = %join_err, "git apply --check spawn_blocking task failed to join");
            ToolError::execution_failed(format!("git apply --check panicked: {join_err}"))
        })?
        .map_err(|e| ToolError::execution_failed(format!("git apply --check failed: {e}")))?;
        let stdout = String::from_utf8_lossy(&out.stdout).to_string();
        let stderr = String::from_utf8_lossy(&out.stderr).to_string();
        ToolResult::json(&json!({
            "attempt_id": attempt_id,
            "patch_path": patch_ref,

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Confirm git is reachable in the app's own environment: `which git` from the same launch context
  2. Restart the app from a shell with a full PATH, or fix the launcher/service PATH to include git
  3. Install git on the machine/container where Codewhale runs, not just on your workstation

Example fix

# before
$ codewhale   # launched via desktop launcher, PATH lacks git
# task attempt check -> ToolError: git not found

# after
$ echo $PATH   # verify
$ codewhale   # started from login shell containing $(dirname $(which git))
Defensive patterns

Strategy: validation

Validate before calling

if which::which("git").is_err() {
    return Err(ToolError::invalid_input(
        "git is required to validate task patches; install git or fix PATH",
    ));
}

Type guard

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

Prevention

When it happens

Trigger: Invoking the task-attempt apply/dry-run path (validating a stored patch with git apply --check) in an environment where the git executable is missing from PATH.

Common situations: Codewhale launched from a GUI, service manager, or IDE plugin whose PATH omits git; minimal containers; remote/SSH sessions with a stripped profile; git uninstalled after the session started.

Related errors


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