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

  1. Re-run with a more specific task name or include the scope/directory (e.g. `frontend:build` or the full unique name)
  2. Use the candidate list printed in the error to pick the exact task name
  3. Rename duplicate tasks in the relevant config files so names are unique per query
  4. 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

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-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/ee42a1477129b8b5. Report an issue: GitHub.