{"record":{"id":"f408f40dd5e1b93d","repo":"nikivdev/code","slug":"failed-to-run-ai-task-sh-e","errorCode":null,"errorMessage":"failed to run ai-task.sh: {e}","messagePattern":"failed to run ai-task\\.sh: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/explain_commits.rs","lineNumber":249,"sourceCode":"            \"5\",\n        ])\n        .output();\n\n    match output {\n        Ok(out) if out.status.success() => {\n            let text = String::from_utf8_lossy(&out.stdout).trim().to_string();\n            if text.is_empty() {\n                Ok(\"(AI returned empty response)\".to_string())\n            } else {\n                Ok(text)\n            }\n        }\n        Ok(out) => {\n            let stderr = String::from_utf8_lossy(&out.stderr);\n            bail!(\"ai-task.sh failed: {}\", stderr.trim());\n        }\n        Err(e) => {\n            bail!(\"failed to run ai-task.sh: {e}\");\n        }\n    }\n}\n\n// -- Markdown output --\n\nfn slugify(s: &str) -> String {\n    s.chars()\n        .map(|c| {\n            if c.is_alphanumeric() || c == '-' {\n                c.to_ascii_lowercase()\n            } else if c == ' ' || c == '_' || c == '/' {\n                '-'\n            } else {\n                '\\0'\n            }\n        })\n        .filter(|c| *c != '\\0')","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/explain_commits.rs#L231-L267","documentation":"Raised when `call_ai_explain` cannot spawn ai-task.sh at all — the `Err(e)` arm of the process launch. Unlike the non-zero-exit case, here the script never ran: the error wraps the OS-level spawn failure.","triggerScenarios":"Command::new(\"ai-task.sh\").output() returns Err at src/explain_commits.rs:249 — typically the file does not exist, is not executable, or the shell interpreter is missing on PATH.","commonSituations":"Fresh clone without the scripts/ setup step executed; file lost execute bit after copying on a filesystem without permissions; PATH differs in CI or non-interactive shells; script moved/renamed in a newer version.","solutions":["Ensure ai-task.sh exists at the expected location (repo scripts directory) and run any repo setup/bootstrap step","Make it executable: chmod +x ai-task.sh","Verify it is reachable via PATH from the shell running f (echo $PATH; which ai-task.sh)","Check that a POSIX shell (/bin/sh or bash) is installed — required on minimal containers/Windows WSL","Confirm your version of the repo still ships ai-task.sh (it may have moved in an update)"],"exampleFix":"// before\nf explain-last --ai   // failed to run ai-task.sh: No such file or directory\n// after\nchmod +x scripts/ai-task.sh && export PATH=\"$PWD/scripts:$PATH\"\nf explain-last --ai","handlingStrategy":"validation","validationCode":"// ensure the script is present and executable before invoking\nlet p = std::path::Path::new(\"scripts/ai-task.sh\");\nif !p.exists() { bail!(\"ai-task.sh not found — run repo setup/bootstrap\"); }\n#[cfg(unix)]\n{\n    use std::os::unix::fs::PermissionsExt;\n    if p.metadata()?.permissions().mode() & 0o111 == 0 {\n        bail!(\"ai-task.sh is not executable — chmod +x it\");\n    }\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().starts_with(\"failed to run ai-task.sh\") => {\n        eprintln!(\"Cannot launch ai-task.sh ({e}); check path/permissions\");\n    }\n    other => other?,\n}","preventionTips":["Run the repo's setup/bootstrap step on fresh clones","chmod +x scripts after copying files across filesystems","Ensure the script's directory is on PATH in CI and non-interactive shells","Install a POSIX shell in minimal container images"],"tags":["subprocess","script","ai","spawn"],"backgroundTag":"command-not-found","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}