{"record":{"id":"5af094261443eff7","repo":"aaif-goose/goose","slug":"failed-to-check-directory-contents","errorCode":null,"errorMessage":"Failed to check directory contents: {}","messagePattern":"Failed to check directory contents: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/recipes/github_recipe.rs","lineNumber":303,"sourceCode":"                    }\n                }\n            }\n        }\n    }\n\n    Ok(recipes)\n}\n\nfn check_github_directory_for_recipe(repo: &str, dir_name: &str) -> Result<RecipeInfo> {\n    use serde_json::Value;\n    use std::process::Command;\n\n    // Check directory contents for recipe files\n    let output = Command::new(\"gh\")\n        .args([\"api\", &format!(\"repos/{}/contents/{}\", repo, dir_name)])\n        .set_no_window()\n        .output()\n        .map_err(|e| anyhow!(\"Failed to check directory contents: {}\", e))?;\n\n    if !output.status.success() {\n        return Err(anyhow!(\"Failed to access directory: {}\", dir_name));\n    }\n\n    let contents: Value = serde_json::from_slice(&output.stdout)\n        .map_err(|e| anyhow!(\"Failed to parse directory contents: {}\", e))?;\n\n    if let Some(items) = contents.as_array() {\n        for item in items {\n            if let Some(name) = item.get(\"name\").and_then(|n| n.as_str()) {\n                if RECIPE_FILE_EXTENSIONS\n                    .iter()\n                    .any(|ext| name == format!(\"recipe.{}\", ext))\n                {\n                    // Found a recipe file, get its content\n                    return get_github_recipe_info(repo, dir_name, name);\n                }","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/recipes/github_recipe.rs#L285-L321","documentation":"While discovering recipes, goose probes each top-level directory with `gh api repos/<repo>/contents/<dir>` (crates/goose-cli/src/recipes/github_recipe.rs:292-304). This error is the spawn io failure of that per-directory call — the gh process could not be executed. It carries the io error text, unlike the static variants elsewhere.","triggerScenarios":"Same io class as [135] but hit on the per-directory loop: gh removed from PATH or replaced mid-run, exec permission/format error, or process-creation resource limits reached while iterating many directories.","commonSituations":"Rare in practice since the parent call succeeded seconds earlier; appears with PATH instability in wrappers, concurrent gh upgrades, or containers hitting the process limit during discovery of large recipe repos.","solutions":["Verify gh still resolves right after the failure: `command -v gh`","Re-run discovery; transient EAGAIN at spawn clears when load drops","Stabilize the environment (consistent PATH, no mid-run binary swaps) for tooling that shells out repeatedly"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Probe one directory the same way goose does\ndir=$(gh api \"repos/$GOOSE_RECIPE_GITHUB_REPO/contents\" --jq '.[0].name')\ngh api \"repos/$GOOSE_RECIPE_GITHUB_REPO/contents/$dir\" >/dev/null && echo \"per-dir probe OK\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep gh resolvable for the entire discovery loop (stable PATH)","Skip or cache discovery for huge recipe repos to limit repeated gh spawns"],"tags":["goose-cli","github-cli","api","external-tool"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}