nikivdev/code · error

Could not parse task name from AI response: '{}'

Error message

Could not parse task name from AI response: '{}'

What it means

extract_task_name matches the cleaned AI response against discovered task names (case-insensitive exact match). When no task name matches, it bails with the original response so the developer can see what the model returned. It is reached via the 'task:' structured prefix or the bare-text fallback in parse_ask_response.

Source

Thrown at src/ask.rs:682

            .to_lowercase()
            .contains(&task.task.name.to_lowercase())
        {
            return Ok(task.task.name.clone());
        }
    }

    let cleaned = response
        .trim_start_matches(|c: char| !c.is_alphanumeric())
        .trim_end_matches(|c: char| !c.is_alphanumeric() && c != '-' && c != '_')
        .to_string();

    for task in tasks {
        if task.task.name.eq_ignore_ascii_case(&cleaned) {
            return Ok(task.task.name.clone());
        }
    }

    bail!("Could not parse task name from AI response: '{}'", response)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::config::TaskConfig;

    fn make_discovered(name: &str) -> DiscoveredTask {
        DiscoveredTask {
            task: TaskConfig {
                name: name.to_string(),
                command: format!("echo {}", name),
                delegate_to_hub: false,
                activate_on_cd_to_root: false,
                dependencies: Vec::new(),
                description: None,
                shortcuts: Vec::new(),
                interactive: false,

View on GitHub (pinned to a747e741ae)

Solutions

  1. Apply normalize_name (strip '-', '_', lowercase) to both sides before comparing, matching how other lookups in the file work
  2. Log the response and the available task list, then re-prompt the AI to answer with an exact task name
  3. Confirm the tasks passed to parse_ask_response are current (re-run discovery)
  4. Fall back to interactive task selection when no match is found

Example fix

// before
for task in tasks {
    if task.task.name.eq_ignore_ascii_case(&cleaned) {
        return Ok(task.task.name.clone());
    }
}
// after
let wanted = normalize_name(&cleaned);
for task in tasks {
    if normalize_name(&task.task.name) == wanted {
        return Ok(task.task.name.clone());
    }
}
bail!("Could not parse task name from AI response: '{}'", response);
Defensive patterns

Strategy: fallback

Validate before calling

fn task_name_is_known(name: &str, tasks: &[DiscoveredTask]) -> bool {
    tasks.iter().any(|t| t.task.name.eq_ignore_ascii_case(name.trim()))
}

Try / catch

match extract_task_name(cleaned, tasks) {
    Err(_) => {
        eprintln!("Could not match a task; choose one manually:");
        prompt_task_selection(tasks)
    }
    Ok(name) => name,
}

Prevention

When it happens

Trigger: AI answers 'task: build-prod' when the task is named 'build_prod' or 'build prod'; 'task:' prefix with a description instead of the name; bare-text answer that mentions a task but isn't an exact name; the task was removed/renamed after discovery.

Common situations: Model paraphrases task names; hyphen/underscore mismatch (only eq_ignore_ascii_case is applied, not the normalize_name fuzzy match used elsewhere); stale cached task list.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/cc3b1694731c455b. Report an issue: GitHub.