{"record":{"id":"705e5d8d2eaa515b","repo":"aaif-goose/goose","slug":"recipe-file-is-invalid","errorCode":null,"errorMessage":"{} recipe file is invalid: {}","messagePattern":"(.+?) recipe file is invalid: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-cli/src/commands/recipe.rs","lineNumber":14,"sourceCode":"use anyhow::Result;\nuse console::style;\nuse goose::recipe::validate_recipe::validate_recipe_template_from_file;\nuse std::collections::HashMap;\n\nuse crate::recipes::github_recipe::RecipeSource;\nuse crate::recipes::search_recipe::{list_available_recipes, load_recipe_file};\nuse goose::recipe_deeplink;\n\npub fn handle_validate(recipe_name: &str) -> Result<()> {\n    // Load and validate the recipe file\n    let recipe_file = load_recipe_file(recipe_name)?;\n    validate_recipe_template_from_file(&recipe_file).map_err(|err| {\n        anyhow::anyhow!(\n            \"{} recipe file is invalid: {}\",\n            style(\"✗\").red().bold(),\n            err\n        )\n    })?;\n    println!(\"{} recipe file is valid\", style(\"✓\").green().bold());\n    Ok(())\n}\n\npub fn handle_deeplink(recipe_name: &str, params: &[String]) -> Result<String> {\n    let params_map = parse_params(params)?;\n    match generate_deeplink(recipe_name, params_map) {\n        Ok((deeplink_url, recipe)) => {\n            println!(\n                \"{} Generated deeplink for: {}\",\n                style(\"✓\").green().bold(),\n                recipe.title\n            );","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-cli/src/commands/recipe.rs#L1-L32","documentation":"`goose recipe validate <name>` loads the recipe file and runs schema/template validation via validate_recipe_template_from_file. Any schema violation — including prompt placeholders like `{{ name }}` with no matching declared parameter — is wrapped with this message; the placeholder carries the validator's specific finding.","triggerScenarios":"Validating a recipe whose YAML is malformed, missing required fields (title/prompt/instructions), or whose prompt template references parameters that are not declared, as exercised by the invalid-recipe test in this file.","commonSituations":"Hand-edited recipes; recipes copied from blog posts with an outdated schema; goose upgrades tightening validation rules; renamed fields.","solutions":["Read the appended validator message — it pinpoints the offending field or placeholder","Fix YAML syntax and required fields per the goose recipe schema (title, description, prompt, instructions, declared parameters)","Diff against a known-good recipe from `goose recipe list` or the repo's tests","Re-run `goose recipe validate` after every edit instead of discovering failures at run time"],"exampleFix":"# before (placeholder {{ name }} never declared)\ntitle: \"Reviewer\"\ndescription: \"Reviews code\"\nprompt: \"Review {{ name }} for defects\"\ninstructions: \"Be strict.\"\n\n# after\n_title: null is not needed; declare the parameter:_\ntitle: \"Reviewer\"\ndescription: \"Reviews code\"\nprompt: \"Review {{ name }} for defects\"\ninstructions: \"Be strict.\"\nparameters:\n  - name: name\n    type: string\n    description: Component to review\n    default: src","handlingStrategy":"validation","validationCode":"# Validate in the loop, not at run time\ngoose recipe validate \"$RECIPE\" || { echo 'fix recipe schema before proceeding' >&2; exit 1; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run `goose recipe validate` in CI for every recipe change","Declare every placeholder used in prompt/instructions as a parameter","Diff against a known-good recipe when validation messages are unclear"],"tags":["recipe","validation","yaml","schema","cli"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}