{"record":{"id":"e68ddfefaa6cbfea","repo":"nikivdev/code","slug":"failed-to-select-recipe","errorCode":null,"errorMessage":"failed to select recipe","messagePattern":"failed to select recipe","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/recipe.rs","lineNumber":125,"sourceCode":"    }\n    for recipe in filtered {\n        println!(\n            \"{:<7} {:<36} {}\",\n            recipe.scope.as_str(),\n            recipe.id,\n            recipe.name\n        );\n    }\n    Ok(())\n}\n\nfn run_recipe(opts: RecipeRunOpts) -> Result<()> {\n    let recipes = load_recipes(opts.scope, opts.global_dir.as_deref())?;\n    let recipe = match select_recipe(&recipes, &opts.selector) {\n        Ok(recipe) => recipe,\n        Err(err) => {\n            eprintln!(\"{err}\");\n            bail!(\"failed to select recipe\")\n        }\n    };\n\n    let cwd = resolve_cwd(opts.cwd.as_deref())?;\n\n    println!(\n        \"Running recipe {} ({}) from {}\",\n        recipe.id,\n        recipe.scope.as_str(),\n        recipe.path.display()\n    );\n    println!(\"cwd: {}\", cwd.display());\n    match &recipe.runner {\n        RecipeRunner::Shell { shell, command } => {\n            let shell_bin = resolve_shell_bin(shell);\n            let shell_cmd = command.trim();\n            println!(\"engine: shell\");\n            println!(\"shell: {}\", shell_bin);","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/recipe.rs#L107-L143","documentation":"`run_recipe` wraps any failure from `select_recipe` with this generic top-level message after printing the specific reason to stderr. The library separates the detailed selector diagnostic (empty/ambiguous/no-match) from the exit error so the CLI exits with a clean failure line.","triggerScenarios":"Calling `run_recipe` (via `run`) with a selector that is empty, matches no recipe, or matches multiple recipes — the real cause is printed on stderr by `select_recipe` (or `ambiguous_selector_error`) just before this bail.","commonSituations":"Typos in the recipe id on the command line; shell expanding an empty variable (`f recipe run \"$MY_SELECTOR\"` with unset var); two recipes sharing the same display name; referencing a recipe from a scope/directory that isn't loaded.","solutions":["Read the stderr line above the error (e.g. 'no recipe matched' or the ambiguity list) and use the exact recipe id","List available recipes (the tool's list command) and copy an id verbatim","Quote/validate the selector variable in your shell so it isn't empty","Rename duplicate recipe display names or select by unique id instead of name"],"exampleFix":"// before\n$ f recipe run \"$SEL\"\nfailed to select recipe\n// after\n$ f recipe list        # find ids\n$ f recipe run lint-all  # exact id, no empty variable","handlingStrategy":"validation","validationCode":"// preflight: reject empty selectors at the call site\nfn ensure_selector(sel: &str) -> Result<&str, String> {\n    let t = sel.trim();\n    if t.is_empty() { Err(\"selector must be a non-empty recipe id\".into()) } else { Ok(t) }\n}","typeGuard":"fn is_valid_selector(sel: &str) -> bool {\n    !sel.trim().is_empty()\n}","tryCatchPattern":"if let Err(e) = run() {\n    let msg = e.to_string();\n    if msg.contains(\"failed to select recipe\") {\n        eprintln!(\"see stderr above for the selector detail; run the list command for valid ids\");\n        std::process::exit(2);\n    }\n    return Err(e);\n}","preventionTips":["Always pass the recipe id, not a free-form name","Quote and default-check shell variables used as selectors","List recipes before scripting against them","Prefer unique ids when recipe names may collide"],"tags":["cli","recipe-selector","input-validation"],"backgroundTag":"recipe-selection-failed","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}