nikivdev/code · error
ambiguous recipe selector
Error message
ambiguous recipe selector
What it means
When no recipe id equals the selector, `select_recipe` falls back to case-insensitive exact-name matching; if more than one recipe shares that name, it prints the candidate list to stderr (via `ambiguous_selector_error`) and bails. The library never guesses between equal-priority matches.
Source
Thrown at src/recipe.rs:637
if normalized.is_empty() {
bail!("empty recipe selector")
}
if let Some(recipe) = recipes.iter().find(|r| r.id == normalized) {
return Ok(recipe);
}
let lowered = normalized.to_ascii_lowercase();
let exact_name: Vec<&Recipe> = recipes
.iter()
.filter(|r| r.name.to_ascii_lowercase() == lowered)
.collect();
if exact_name.len() == 1 {
return Ok(exact_name[0]);
}
if exact_name.len() > 1 {
ambiguous_selector_error(selector, &exact_name)?;
bail!("ambiguous recipe selector")
}
let contains: Vec<&Recipe> = recipes
.iter()
.filter(|r| {
r.id.to_ascii_lowercase().contains(&lowered)
|| r.name.to_ascii_lowercase().contains(&lowered)
})
.collect();
if contains.len() == 1 {
return Ok(contains[0]);
}
if contains.is_empty() {
bail!("no recipe matched '{}'", selector);
}
ambiguous_selector_error(selector, &contains)?;
bail!("ambiguous recipe selector")
}View on GitHub (pinned to a747e741ae)
Solutions
- Use the unique recipe id instead of the display name (ids are listed on stderr and by the list command)
- Rename one of the colliding recipes so names are unique
- Restrict the scope (global vs project) so only one matching recipe is loaded
- Deduplicate duplicated recipe files in the recipe directories
Example fix
// before: two recipes named "Build" $ f recipe run build recipe selector 'build' matched multiple recipes: - build.global (Build) - build.web (Build) ambiguous recipe selector // after $ f recipe run build.web # select by unique id
Defensive patterns
Strategy: validation
Validate before calling
// preflight: ensure the name resolves to exactly one recipe before selecting
fn unique_name<'a>(recipes: &'a [Recipe], name: &str) -> Option<&'a Recipe> {
let lowered = name.to_ascii_lowercase();
let m: Vec<&Recipe> = recipes.iter().filter(|r| r.name.to_ascii_lowercase() == lowered).collect();
if m.len() == 1 { Some(m[0]) } else { None } // None => select by id instead
} Try / catch
match run_recipe(opts) {
Err(e) if e.to_string().contains("ambiguous recipe selector") => {
eprintln!("name matched multiple recipes; re-run with a unique recipe id (see stderr list)");
std::process::exit(2);
}
other => other,
} Prevention
- Always script against recipe ids, never display names
- Keep recipe name fields unique across global and project scopes
- Rename copied recipe files and update their name metadata
- On ambiguity, read the stderr list — it names every colliding id
When it happens
Trigger: Selecting by display name (not id) when two or more recipes in the loaded scope have the same (case-insensitively equal) name — e.g. two scopes each defining a recipe named 'build'.
Common situations: Duplicate recipe names across global and project recipe directories; copied recipe files where the name field wasn't changed; team recipes imported under the same name as a personal recipe.
Related errors
- AI task '{}' is ambiguous. Matches: - {} Try one of the fu
- multiple matches for '{}': {}. Use owner/repo.
- failed to select recipe
- empty recipe selector
- no recipe matched '{}'
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/66a5e3990a5fee3a.
Report an issue: GitHub.