nikivdev/code · warning
(dynamic ambiguous/unresolved task message)
Error message
(dynamic ambiguous/unresolved task message)
What it means
ambiguous_task_error builds a dynamic message listing all discovered tasks matching a query when the match is not unique or cannot be resolved, then throws it via anyhow. The error tells the user their task query was ambiguous or unresolved and enumerates the candidate task names and config paths so they can disambiguate.
Source
Thrown at src/tasks.rs:1174
fn ambiguous_task_error(task_name: &str, matches: &[&discover::DiscoveredTask]) -> anyhow::Error {
let mut msg = String::new();
msg.push_str(&format!("task '{}' is ambiguous.\n", task_name));
msg.push_str("Discovered matches:\n");
for task in matches {
msg.push_str(&format!(" - {}\n", task_reference(task)));
}
msg.push_str("Try one of:\n");
for task in matches {
msg.push_str(&format!(
" f {}:{}\n f run --config {} {}\n",
task.scope,
task.task.name,
task.config_path.display(),
task.task.name
));
}
anyhow::anyhow!(msg.trim_end().to_string())
}
fn resolve_ambiguous_task_match<'a>(
query: &str,
matches: &[&'a discover::DiscoveredTask],
task_resolution: Option<&TaskResolutionConfig>,
) -> Result<&'a discover::DiscoveredTask> {
let Some(policy) = task_resolution else {
return Err(ambiguous_task_error(query, matches));
};
let mut route_scope: Option<&str> = None;
for (task, scope) in &policy.routes {
if task.eq_ignore_ascii_case(query)
|| matches
.iter()
.any(|m| m.task.name.eq_ignore_ascii_case(task))
{View on GitHub (pinned to a747e741ae)
Solutions
- Re-run with a more specific task name or include the scope/directory (e.g. `frontend:build` or the full unique name)
- Use the candidate list printed in the error to pick the exact task name
- Rename duplicate tasks in the relevant config files so names are unique per query
- Configure task resolution precedence (task_resolution config) to disambiguate common names
Example fix
// before (CLI) f run build // after (disambiguated) f run frontend:build # or use the full unique task name from the error's candidate list
Defensive patterns
Strategy: try-catch
Validate before calling
let matches = discover_tasks_matching(query)?;
if matches.len() > 1 {
eprintln!("query '{}' matches {} tasks: {:?}; qualify with a scope", query,
matches.len(), matches.iter().map(|m| &m.task.name).collect::<Vec<_>>());
return;
} Try / catch
match select_discovered_task(query) {
Ok(task) => run_task(task),
Err(e) if e.to_string().contains("Multiple tasks") || e.to_string().contains("ambiguous") => {
eprintln!("{}", e); // error already lists candidates
eprintln!("re-run with a more specific name or scope");
}
Err(e) => return Err(e),
} Prevention
- Name tasks uniquely across scopes and directories
- Pass scope-qualified names when multiple projects define the same verb
- Configure resolution precedence for recurring ambiguous names
- Read the candidate list in the message — it enumerates every matching config path
When it happens
Trigger: Calling ambiguous_task_error (via select_discovered_task or resolve_ambiguous_task_match) when a short task query matches multiple discovered tasks (different scopes/dirs sharing a name) or matches none in a way the resolver cannot settle, e.g. `f run build` when both frontend and backend define `build`.
Common situations: Duplicate task names across projects/scopes in the workspace; partial task name matching several entries; task defined in multiple config files; typos that still fuzzy-match several candidates.
Related errors
- AI task '{}' is ambiguous. Matches: - {} Try one of the fu
- multiple matches for '{}': {}. Use owner/repo.
- ambiguous recipe selector
- Review todo id '{}' is ambiguous
- Todo id '{}' is ambiguous
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/ee42a1477129b8b5.
Report an issue: GitHub.