{"record":{"id":"d889e902d8aca73b","repo":"aaif-goose/goose","slug":"github-api-request-failed","errorCode":null,"errorMessage":"GitHub API request failed: {}","messagePattern":"GitHub API request failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/recipes/github_recipe.rs","lineNumber":267,"sourceCode":"}\n\nfn discover_github_recipes(repo: &str) -> Result<Vec<RecipeInfo>> {\n    use serde_json::Value;\n    use std::process::Command;\n\n    // Ensure GitHub CLI is authenticated\n    ensure_gh_authenticated()?;\n\n    // Get repository contents using GitHub CLI\n    let output = Command::new(\"gh\")\n        .args([\"api\", &format!(\"repos/{}/contents\", repo)])\n        .set_no_window()\n        .output()\n        .map_err(|e| anyhow!(\"Failed to fetch repository contents using 'gh api' command (executed when GOOSE_RECIPE_GITHUB_REPO is configured). This requires GitHub CLI (gh) to be installed and authenticated. Error: {}\", e))?;\n\n    if !output.status.success() {\n        let error_msg = String::from_utf8_lossy(&output.stderr);\n        return Err(anyhow!(\"GitHub API request failed: {}\", error_msg));\n    }\n\n    let contents: Value = serde_json::from_slice(&output.stdout)\n        .map_err(|e| anyhow!(\"Failed to parse GitHub API response: {}\", e))?;\n\n    let mut recipes = Vec::new();\n\n    if let Some(items) = contents.as_array() {\n        for item in items {\n            if let (Some(name), Some(item_type)) = (\n                item.get(\"name\").and_then(|n| n.as_str()),\n                item.get(\"type\").and_then(|t| t.as_str()),\n            ) {\n                if item_type == \"dir\" {\n                    // Check if this directory contains a recipe file\n                    if let Ok(recipe_info) = check_github_directory_for_recipe(repo, name) {\n                        recipes.push(recipe_info);\n                    }","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/recipes/github_recipe.rs#L249-L285","documentation":"The `gh api repos/<repo>/contents` call executed but exited non-zero; goose surfaces gh's stderr verbatim after this prefix (crates/goose-cli/src/recipes/github_recipe.rs:265-268). The stderr text is the authoritative cause — typically HTTP 404 (no such repo), 403 (rate limit or missing scope), or 401 (bad token).","triggerScenarios":"GOOSE_RECIPE_GITHUB_REPO names a nonexistent repo; the authenticated token lacks access to a private repo; GitHub API rate limit exceeded; network/proxy returning an error gh reports as failure.","commonSituations":"Typo in the env var value, private org repo where the token needs SSO authorization, heavy scripting hitting the secondary rate limit, or corporate proxies intercepting api.github.com.","solutions":["Run the same call manually to see the exact status: `gh api repos/<owner>/<repo>/contents` — 404 means wrong name/no access, 403 usually rate limit","Fix GOOSE_RECIPE_GITHUB_REPO to the correct owner/repo and confirm access with `gh repo view`","If rate-limited, wait for the reset window (check `gh api rate_limit`) or authenticate with a token that raises the limit"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"# Check the endpoint and rate limit headroom first\ngh api \"repos/$GOOSE_RECIPE_GITHUB_REPO/contents\" --jq 'length'\ngh api rate_limit --jq '.resources.core'","typeGuard":null,"tryCatchPattern":"// Rust: always surface gh's stderr body with the exit status\nif !output.status.success() {\n    anyhow::bail!(\n        \"GitHub API request failed ({}): {}\",\n        output.status,\n        String::from_utf8_lossy(&output.stderr)\n    );\n}","preventionTips":["Verify owner/repo spelling with `gh repo view` before configuring goose","Authenticate with a token that has access to private/SSO recipe repos","Back off when scripting discovery to avoid secondary rate limits"],"tags":["goose-cli","github-api","http-error","rate-limit"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}