{"record":{"id":"07522e35ee46dd16","repo":"aaif-goose/goose","slug":"failed-to-parse-directory-contents","errorCode":null,"errorMessage":"Failed to parse directory contents: {}","messagePattern":"Failed to parse directory contents: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/recipes/github_recipe.rs","lineNumber":310,"sourceCode":"}\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                }\n            }\n        }\n    }\n\n    Err(anyhow!(\"No recipe file found in directory: {}\", dir_name))\n}\n","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/recipes/github_recipe.rs#L292-L328","documentation":"Raised while listing a recipe directory from GitHub: goose shells out to `gh api repos/{repo}/contents/{dir}` and parses stdout with serde_json::from_slice. This error means gh exited successfully but printed bytes that are not valid JSON. Usually gh wrote an auth prompt, a warning, or nothing to stdout while the real error went to stderr.","triggerScenarios":"Running `goose recipe` commands that load recipes from a GitHub repo when `gh api repos/{repo}/contents/{dir_name}` returns non-JSON stdout: expired token emitting an interactive `gh auth login` prompt text, a corporate proxy returning an HTML error page, or empty stdout from a misbehaving gh wrapper.","commonSituations":"Expired or partially configured `gh auth login` state; GH_TOKEN/ GITHUB_TOKEN env var set to an invalid value that overrides keyring auth; proxies or GH_HOST misconfiguration; gh version mismatches after OS upgrades.","solutions":["Run `gh api \"repos/{owner}/{repo}/contents/{dir}\"` manually and inspect stdout — if it is not JSON, fix the gh problem it reveals.","Run `gh auth status` and re-authenticate with `gh auth login` (or fix the GH_TOKEN env var) if the token is expired/invalid.","Check GH_HOST and proxy settings if a non-GitHub response (e.g. HTML) is returned.","Update gh to a current version if output formatting differs."],"exampleFix":"// before: gh token expired, gh prints prompt text to stdout\n$ gh api repos/owner/repo/contents/recipes\nTo get started with GitHub CLI, please run: gh auth login\n\n// after\n$ gh auth login\n$ gh api repos/owner/repo/contents/recipes\n[{\"name\": \"my-recipe\", \"path\": \"recipes/my-recipe\", ...}]","handlingStrategy":"validation","validationCode":"# pre-flight before goose recipe commands that hit GitHub\ngh auth status >/dev/null 2>&1 || gh auth login\ngh api \"repos/${REPO}/contents/${DIR}\" >/dev/null && echo \"directory listing is valid JSON\"","typeGuard":null,"tryCatchPattern":"if let Err(e) = load_recipe_from_github(repo, dir) {\n    if e.to_string().starts_with(\"Failed to parse directory contents\") {\n        eprintln!(\"gh returned non-JSON; check `gh auth status` and proxies\");\n    }\n    return Err(e);\n}","preventionTips":["Keep `gh auth token` valid; scripts should run `gh auth status` as a preflight.","Don't wrap gh with aliases or pipes that add text to stdout.","Pin a known-good gh version in CI images."],"tags":["github","gh-cli","json","parsing","recipes","authentication"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}