{"record":{"id":"6f7cf48e411a4ae2","repo":"aaif-goose/goose","slug":"failed-to-parse-file-info","errorCode":null,"errorMessage":"Failed to parse file info: {}","messagePattern":"Failed to parse file info: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/recipes/github_recipe.rs","lineNumber":352,"sourceCode":"    let output = Command::new(\"gh\")\n        .args([\n            \"api\",\n            &format!(\"repos/{}/contents/{}/{}\", repo, dir_name, recipe_filename),\n        ])\n        .set_no_window()\n        .output()\n        .map_err(|e| anyhow!(\"Failed to get recipe file content: {}\", e))?;\n\n    if !output.status.success() {\n        return Err(anyhow!(\n            \"Failed to access recipe file: {}/{}\",\n            dir_name,\n            recipe_filename\n        ));\n    }\n\n    let file_info: Value = serde_json::from_slice(&output.stdout)\n        .map_err(|e| anyhow!(\"Failed to parse file info: {}\", e))?;\n\n    if let Some(content_b64) = file_info.get(\"content\").and_then(|c| c.as_str()) {\n        // Decode base64 content\n        use base64::{engine::general_purpose, Engine as _};\n        let content_bytes = general_purpose::STANDARD\n            .decode(content_b64.replace('\\n', \"\"))\n            .map_err(|e| anyhow!(\"Failed to decode base64 content: {}\", e))?;\n\n        let content = String::from_utf8(content_bytes)\n            .map_err(|e| anyhow!(\"Failed to convert content to string: {}\", e))?;\n\n        // Parse the recipe content\n        let (recipe, _) = parse_recipe_content(&content, Some(format!(\"{}/{}\", repo, dir_name)))?;\n\n        return Ok(RecipeInfo {\n            name: dir_name.to_string(),\n            source: RecipeSource::GitHub,\n            path: format!(\"{}/{}\", repo, dir_name),","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/recipes/github_recipe.rs#L334-L370","documentation":"After successfully fetching the single recipe file's metadata, `serde_json::from_slice` on gh's stdout failed — the response body was not valid JSON. The directory listing call succeeded, so auth is fine; this points to a mangled response for the file-content endpoint, such as warnings injected into stdout, truncated output, or non-JSON error bodies from a proxy.","triggerScenarios":"gh emitting a deprecation or secondary-rate-limit warning line into stdout before the JSON body; a proxy or GH_HOST gateway rewriting the response; extremely large responses being truncated by pipe buffering limits.","commonSituations":"Corporate proxies modifying responses; gh versions that print notices to stdout instead of stderr; piping through wrappers (gh aliases, tee) that add text.","solutions":["Reproduce manually: `gh api \"repos/{repo}/contents/{dir}/{file}\" | head -c 300` and look for non-JSON prefix lines.","Remove gh aliases or wrappers (check `gh alias list`) that decorate output.","Update gh to a version that keeps notices on stderr.","Retry after a short wait if a transient secondary rate-limit notice was interleaved."],"exampleFix":"# before: gh alias wraps output\n$ gh alias list\napi: api --paginate || echo done   # extra text pollutes stdout\n\n# after\n$ gh alias delete api\n$ goose recipe info owner/repo/my-recipe","handlingStrategy":"validation","validationCode":"# ensure the file endpoint returns pure JSON before relying on goose's parse\ngh api \"repos/${REPO}/contents/${DIR}/recipe.yaml\" | jq -e 'has(\"content\")' >/dev/null \\\n  || echo \"response is not clean JSON — check gh aliases/proxies\"","typeGuard":null,"tryCatchPattern":"if let Err(e) = get_recipe_info(repo, dir) {\n    if e.to_string().starts_with(\"Failed to parse file info\") {\n        eprintln!(\"gh stdout polluted — inspect `gh api .../recipe.yaml` output\");\n    }\n    return Err(e);\n}","preventionTips":["Avoid gh aliases/wrappers that print extra lines to stdout.","Use `gh api --silent`-style hygiene in your own tooling around gh."],"tags":["json","parsing","gh-cli","proxy","recipes"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}