{"record":{"id":"69b47be81b9c0022","repo":"Hmbown/CodeWhale","slug":"git-not-found","errorCode":null,"errorMessage":"git not found","messagePattern":"git not found","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/tasks.rs","lineNumber":831,"sourceCode":"            .task_manager\n            .as_ref()\n            .ok_or_else(|| ToolError::not_available(\"TaskManager is not attached\"))?;\n        let task = read_task_for_input(input, context).await?;\n        let attempt_id = required_str(input, \"attempt_id\")?;\n        let attempt = task\n            .attempts\n            .iter()\n            .find(|attempt| attempt.id == attempt_id)\n            .ok_or_else(|| ToolError::invalid_input(format!(\"Attempt not found: {attempt_id}\")))?;\n        let patch_ref = attempt\n            .patch_path\n            .as_ref()\n            .ok_or_else(|| ToolError::invalid_input(\"Attempt has no patch artifact\"))?;\n        let patch_path = manager.artifact_absolute_path(patch_ref);\n        let workspace = context.workspace.clone();\n        let out = tokio::task::spawn_blocking(move || {\n            crate::dependencies::Git::command()\n                .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, \"git not found\"))?\n                .args([\"apply\", \"--check\"])\n                .arg(&patch_path)\n                .current_dir(&workspace)\n                .output()\n        })\n        .await\n        .map_err(|join_err| {\n            // Surface the otherwise-discarded join error for debugging; the\n            // returned ToolError (and thus user-facing behavior) is unchanged.\n            tracing::debug!(error = %join_err, \"git apply --check spawn_blocking task failed to join\");\n            ToolError::execution_failed(format!(\"git apply --check panicked: {join_err}\"))\n        })?\n        .map_err(|e| ToolError::execution_failed(format!(\"git apply --check failed: {e}\")))?;\n        let stdout = String::from_utf8_lossy(&out.stdout).to_string();\n        let stderr = String::from_utf8_lossy(&out.stderr).to_string();\n        ToolResult::json(&json!({\n            \"attempt_id\": attempt_id,\n            \"patch_path\": patch_ref,","sourceCodeStart":813,"sourceCodeEnd":849,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/tools/tasks.rs#L813-L849","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Confirm git is reachable in the app's own environment: `which git` from the same launch context","Restart the app from a shell with a full PATH, or fix the launcher/service PATH to include git","Install git on the machine/container where Codewhale runs, not just on your workstation"],"exampleFix":"# before\n$ codewhale   # launched via desktop launcher, PATH lacks git\n# task attempt check -> ToolError: git not found\n\n# after\n$ echo $PATH   # verify\n$ codewhale   # started from login shell containing $(dirname $(which git))","handlingStrategy":"validation","validationCode":"if which::which(\"git\").is_err() {\n    return Err(ToolError::invalid_input(\n        \"git is required to validate task patches; install git or fix PATH\",\n    ));\n}","typeGuard":"fn is_git_missing(e: &std::io::Error) -> bool {\n    e.kind() == std::io::ErrorKind::NotFound && e.to_string().contains(\"git not found\")\n}","tryCatchPattern":null,"preventionTips":["Check git availability before enabling task features that apply patches","Test the app's launch environment, not your interactive shell, for PATH completeness","Install git in every container/host where task attempts run"],"tags":["git","tasks","patch","environment","path","rust"],"backgroundTag":"git-executable-not-found","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}