{"record":{"id":"4d2a557cb3f13acd","repo":"aaif-goose/goose","slug":"failed-to-access-recipe-file","errorCode":null,"errorMessage":"Failed to access recipe file: {}/{}","messagePattern":"Failed to access recipe file: (.+?)/(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/recipes/github_recipe.rs","lineNumber":344,"sourceCode":"    Err(anyhow!(\"No recipe file found in directory: {}\", dir_name))\n}\n\nfn get_github_recipe_info(repo: &str, dir_name: &str, recipe_filename: &str) -> Result<RecipeInfo> {\n    use serde_json::Value;\n    use std::process::Command;\n\n    // Get the recipe file content\n    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))?;","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/recipes/github_recipe.rs#L326-L362","documentation":"`gh api repos/{repo}/contents/{dir}/{recipe_filename}` ran but exited non-zero while fetching the recipe file itself. This is an HTTP-level failure surfaced through gh: 404 when the path is wrong (case-sensitive, or the file was renamed between the listing and the fetch), 401/403 for auth or permission problems on private repos, and 403 for primary/secondary rate limits.","triggerScenarios":"Recipe file renamed or deleted between the directory listing and this second API call (race); unauthenticated gh hitting GitHub's rate limit while listing many recipes; accessing a private repo without an authorized token; wrong-case path segments on case-sensitive APIs.","commonSituations":"Scanning large recipe collections until the unauthenticated rate limit trips; upstream repos moving files; tokens lacking repo scope for private recipe repos.","solutions":["Run the exact URL manually: `gh api \"repos/{repo}/contents/{dir}/{file}\"` and read the HTTP status it reports.","If rate-limited (403 with rate limit message), wait for the reset window or authenticate via `gh auth login` to raise the limit.","If 404, verify the file name and its casing against the directory listing.","If 401/403 on a private repo, re-authenticate or grant the token repo access."],"exampleFix":"# before\n$ goose recipe info owner/private-repo/my-recipe\nError: Failed to access recipe file: my-recipe/recipe.yaml\n\n# after\n$ gh auth status   # shows token lacks repo scope\n$ gh auth refresh -h github.com -s repo\n$ goose recipe info owner/private-repo/my-recipe","handlingStrategy":"retry","validationCode":"# confirm the exact path resolves before goose fetches it (case-sensitive)\ngh api \"repos/${REPO}/contents/${DIR}/recipe.yaml\" --jq '.name'","typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match fetch_recipe_file(repo, dir, file) {\n        Err(e) if e.to_string().contains(\"Failed to access recipe file\") && attempt < 2 => {\n            tokio::time::sleep(Duration::from_secs(2u64.pow(attempt))).await; // rate-limit backoff\n        }\n        r => break r,\n    }\n}","preventionTips":["Authenticate gh (higher rate limits) before bulk recipe scans.","Keep filenames stable and lowercase to avoid case-mismatch 404s.","Back off on 403 rate-limit responses instead of hammering the API."],"tags":["github","http","rate-limit","authentication","recipes"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}