{"record":{"id":"a7135f31d3571aa0","repo":"aaif-goose/goose","slug":"recipe-build-failed","errorCode":null,"errorMessage":"Recipe build failed: {}","messagePattern":"Recipe build failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose/src/agents/agent.rs","lineNumber":3960,"sourceCode":"            } else {\n                (\n                    \"Custom recipe from chat\".to_string(),\n                    \"a custom recipe instance from this chat session\".to_string(),\n                )\n            };\n\n        let recipe = Recipe::builder()\n            .title(title)\n            .description(description)\n            .instructions(instructions)\n            .activities(activities)\n            .extensions(extension_configs)\n            .settings(settings)\n            .author(author)\n            .build()\n            .map_err(|e| {\n                tracing::error!(\"Failed to build recipe: {}\", e);\n                anyhow!(\"Recipe build failed: {}\", e)\n            })?;\n\n        tracing::info!(\"Recipe creation completed successfully\");\n        Ok(recipe)\n    }\n}\n\nfn recipe_conversation_history(messages: &Conversation) -> Vec<Message> {\n    // The recipe prompt has no turn-context instructions; drop the blocks.\n    messages\n        .agent_visible_messages()\n        .into_iter()\n        .filter(|message| !message.is_turn_context())\n        .collect()\n}\n\n#[cfg(test)]\nmod tests {","sourceCodeStart":3942,"sourceCodeEnd":3978,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose/src/agents/agent.rs#L3942-L3978","documentation":"Thrown when RecipeBuilder::build() rejects the assembled recipe during LLM recipe generation. build() enforces three invariants (crates/goose/src/recipe/mod.rs:409): a title, a description, and at least one of prompt/instructions. The '{}' is one of those static messages ('Title is required', 'Description is required', or \"At least one of 'prompt' or 'instructions' is required\").","triggerScenarios":"Recipe generation completes but the extracted title/description came out empty, or both instructions and prompt are absent (e.g. every parsing path produced nothing usable), so the final builder validation fails.","commonSituations":"Models returning an empty title/description; upstream parsing fallbacks yielding empty strings; conversations with no derivable subject (tiny or empty transcript).","solutions":["Retry generation with a more descriptive conversation as the source","Use a stronger model that reliably produces title and description","If embedding, supply explicit title/description via the builder instead of relying on extraction","Hand-author the recipe YAML with all required fields"],"exampleFix":"// before\nRecipe::builder()\n    .instructions(instructions)\n    .activities(activities)\n    .build()?; // Err: Title is required\n\n// after\nRecipe::builder()\n    .title(title)\n    .description(description)\n    .instructions(instructions)\n    .activities(activities)\n    .build()?","handlingStrategy":"validation","validationCode":"// Rust — check builder invariants before calling build()\nlet ok = !title.trim().is_empty()\n    && !description.trim().is_empty()\n    && (!instructions.trim().is_empty() || !prompt.trim().is_empty());\nif !ok { /* regenerate or fill in fields explicitly */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set title, description, and instructions (or prompt) on RecipeBuilder — they are required","Provide explicit title/description when generating from thin conversations","Hand-author YAML for recipes you will reuse instead of regenerating"],"tags":["recipe","builder","validation","llm-output"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}