{"record":{"id":"1e0fa98cbe0bfabd","repo":"aaif-goose/goose","slug":"failed-to-get-recipe-content-from-github","errorCode":null,"errorMessage":"Failed to get recipe content from GitHub","messagePattern":"Failed to get recipe content from GitHub","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/recipes/github_recipe.rs","lineNumber":376,"sourceCode":"            .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),\n            title: Some(recipe.title),\n            description: Some(recipe.description),\n        });\n    }\n\n    Err(anyhow!(\"Failed to get recipe content from GitHub\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::path::Path;\n\n    #[test]\n    fn local_repo_path_includes_owner_to_avoid_collisions() {\n        let parent = Path::new(\"goose-recipes\");\n        let first = get_local_repo_path(parent, \"owner-one/shared\").unwrap();\n        let second = get_local_repo_path(parent, \"owner-two/shared\").unwrap();\n\n        assert_ne!(first, second);\n        assert_eq!(first, parent.join(\"owner-one__shared\"));\n        assert_eq!(second, parent.join(\"owner-two__shared\"));\n    }\n","sourceCodeStart":358,"sourceCodeEnd":394,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/recipes/github_recipe.rs#L358-L394","documentation":"The file-info JSON parsed but had no `content` string field, so the function falls through to this catch-all error. GitHub's contents API omits `content` when it cannot inline the payload: files larger than 1 MB (content/encoding returned empty), symlinks, and submodule entries. The recipe file exists, but this code path cannot retrieve its bytes.","triggerScenarios":"A recipe.yaml over 1 MB (huge embedded prompts, vendored data); recipe.yaml implemented as a symlink; the entry being a submodule reference rather than a regular file.","commonSituations":"Recipes that grew organically past the 1 MB contents-API inline limit — the earlier directory listing works, then content extraction silently degrades to this generic message.","solutions":["Check the `size` field of the file in the API response; if > 1048576, split the recipe (move data into separate extension files) or shrink it.","If it is a symlink, replace it with a real file in the upstream repo.","As a workaround, clone the repo locally and load the recipe from the filesystem path instead of via GitHub."],"exampleFix":"# before\n$ gh api repos/o/r/contents/big-recipe/recipe.yaml -q '.size'\n2500000   # > 1MB, contents API returns no content\nError: Failed to get recipe content from GitHub\n\n# after: split oversized recipe\n# big-recipe/recipe.yaml  (keep < 1MB, reference extensions)\n# big-recipe/extensions/*.yaml  (moved bulk content here)","handlingStrategy":"validation","validationCode":"# guard the 1MB inline limit before loading\nsize=$(gh api \"repos/${REPO}/contents/${DIR}/recipe.yaml\" --jq '.size // 0')\n[ \"$size\" -le 1048576 ] || { echo \"recipe.yaml is ${size} bytes (>1MB); contents API omits content\"; exit 1; }","typeGuard":null,"tryCatchPattern":"if err.to_string() == \"Failed to get recipe content from GitHub\" {\n    // content field absent: oversized file, symlink, or submodule entry\n    suggest_clone_and_shrink();\n}","preventionTips":["Split bulky recipes into extension files so recipe.yaml stays under 1 MB.","Never symlink recipe.yaml in recipe repos."],"tags":["github","size-limit","api-limits","recipes","symlink"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}