Hmbown/CodeWhale · error · anyhow::Error
Ambiguous task prefix '{}': matches {} tasks
Error message
Ambiguous task prefix '{}': matches {} tasks What it means
Task id resolution matched two or more visible ids with the given prefix, so the reference is ambiguous and the call is rejected rather than guessing. Exact id matches short-circuit before prefix matching, so this only fires for non-exact prefixes.
Source
Thrown at crates/tui/src/task_manager.rs:2447
) -> Result<String> {
let visible = |record: &TaskRecord| {
owner_session_id.is_none_or(|owner_session_id| {
record.owner_session_id.as_deref() == Some(owner_session_id)
})
};
if tasks.get(id_or_prefix).is_some_and(visible) {
return Ok(id_or_prefix.to_string());
}
let matches = tasks
.iter()
.filter(|(id, record)| id.starts_with(id_or_prefix) && visible(record))
.map(|(id, _)| id)
.cloned()
.collect::<Vec<_>>();
match matches.len() {
0 => bail!("Task not found: {id_or_prefix}"),
1 => Ok(matches[0].clone()),
_ => bail!(
"Ambiguous task prefix '{}': matches {} tasks",
id_or_prefix,
matches.len()
),
}
}
fn resolve_task_id(tasks: &HashMap<String, TaskRecord>, id_or_prefix: &str) -> Result<String> {
resolve_task_id_visible_to(tasks, id_or_prefix, None)
}
fn summarize_json(value: &Value) -> Option<String> {
let text = serde_json::to_string(value).ok()?;
Some(summarize_text(&text, TIMELINE_SUMMARY_LIMIT))
}
fn summarize_text(text: &str, limit: usize) -> String {
let take = limit.saturating_sub(3);View on GitHub (pinned to 0c42157ee5)
Solutions
- Add more hex characters from the displayed id until it is unique; the error reports how many tasks matched.
- Use the complete 21-char id when scripting, since abbreviations are only a convenience for humans.
- When surfacing ids in your own UI, show enough characters (>= 8) to keep prefixes unique in practice.
Example fix
// before
let id = resolve_task_id(&tasks, prefix)?; // 'task_1' ambiguous
// after
// grow the prefix until it is unambiguous
let mut p = prefix.to_string();
loop {
let hits = tasks.keys().filter(|k| k.starts_with(&p)).count();
if hits == 1 { break; }
if hits == 0 { bail!("no such task"); }
p.push(next_char_from_known_id(&p));
}
let id = resolve_task_id(&tasks, &p)?; Defensive patterns
Strategy: validation
Validate before calling
fn prefix_is_unique(tasks: &HashMap<String, TaskRecord>, prefix: &str) -> bool {
tasks.keys().filter(|id| id.starts_with(prefix)).count() == 1
} Prevention
- Default to the full id in scripts; abbreviate only in interactive contexts.
- Show at least 8 hex chars of the id in UIs to keep prefixes practically unique.
- On ambiguity the error names the match count: add characters from the candidates shown in the task list.
When it happens
Trigger: Passing a short prefix like 'task_a' or a 2-3 hex-char fragment that is a prefix of several task ids, e.g. after many tasks accumulate sharing the 'task_' stem; using the first characters of two ids that differ only late in the string.
Common situations: Long-lived task stores with hundreds of records; scripts that abbreviate ids to a fixed short length; UIs that display truncated ids which users then transcribe.
Related errors
- Task not found: {id_or_prefix}
- Task prompt cannot be empty
- Invalid preallocated task id: expected task_<16hex>
- Task id already exists: {}
- Failed to promote staged task {}: {promote_err}
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/c3a0257789345e0c.
Report an issue: GitHub.