{"record":{"id":"bfbb3870bcb01a07","repo":"aaif-goose/goose","slug":"no-recipe-file-found-in-directory","errorCode":null,"errorMessage":"No recipe file found in directory: {}","messagePattern":"No recipe file found in directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/recipes/github_recipe.rs","lineNumber":326,"sourceCode":"\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\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!(","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/recipes/github_recipe.rs#L308-L344","documentation":"The directory listing from GitHub succeeded and parsed, but no entry matched a file named exactly `recipe.yaml` or `recipe.json` (goose::recipe::RECIPE_FILE_EXTENSIONS is &[\"yaml\", \"json\"]). Goose requires every recipe directory in a repo to contain one of those exact filenames. Notably `recipe.yml` does NOT match.","triggerScenarios":"Loading a GitHub recipe whose subdirectory exists but contains a file named differently: `recipe.yml` instead of `recipe.yaml`, `Recipe.yaml` (case mismatch), or only a README / other files.","commonSituations":"Recipe authors naming the file recipe.yml out of habit (the .yml extension is not accepted here); renamed files in the upstream repo; a directory that is not actually a recipe but sits in the scanned path.","solutions":["Check the directory contents via `gh api repos/{repo}/contents/{dir_name}` and look for a file literally named recipe.yaml or recipe.json.","If the file is recipe.yml, rename it to recipe.yaml in the upstream repo.","Verify exact casing and that no subdirectory nesting moved the recipe file."],"exampleFix":"# before (directory listing):\n# [{\"name\": \"recipe.yml\"}, {\"name\": \"README.md\"}]\n# -> Err: No recipe file found in directory: my-recipe\n\n# after\ngit mv my-recipe/recipe.yml my-recipe/recipe.yaml\ngit commit -m \"rename recipe file to recipe.yaml\" && git push","handlingStrategy":"validation","validationCode":"# verify the exact filename exists before goose scans it\ngh api \"repos/${REPO}/contents/${DIR}\" --jq '.[].name' | grep -Ex 'recipe.(yaml|json)' \\\n  || echo \"missing recipe.yaml/recipe.json in ${DIR}\"","typeGuard":null,"tryCatchPattern":"match list_recipe_dir(repo, dir) {\n    Err(e) if e.to_string().contains(\"No recipe file found\") => {\n        // directory exists but is not a recipe; skip or fix upstream\n        skip(dir);\n    }\n    other => other,\n}","preventionTips":["Name recipe files exactly recipe.yaml or recipe.json — not recipe.yml.","Add a repo CI check that every recipe directory contains an accepted filename."],"tags":["recipes","github","validation","file-naming"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}