nikivdev/code · error
Could not parse AI response: '{}'
Error message
Could not parse AI response: '{}' What it means
When the cleaned AI response is neither a structured 'task:'/'cmd:' line, an 'f ...' command, a known task name, nor a command-like token whose subcommand is valid, parse_ask_response gives up and includes the raw text in the error so the developer can see what the model said.
Source
Thrown at src/ask.rs:461
return Ok(selection);
}
}
if cleaned.starts_with("f ") || cleaned.starts_with("flow ") {
let command = normalize_command(cleaned, valid_subcommands)?;
return Ok(AskSelection::Command { command });
}
if let Ok(task_name) = extract_task_name(cleaned, tasks) {
return Ok(AskSelection::Task { name: task_name });
}
if is_command_like(cleaned, valid_subcommands) {
let command = normalize_command(cleaned, valid_subcommands)?;
return Ok(AskSelection::Command { command });
}
bail!("Could not parse AI response: '{}'", cleaned);
}
fn parse_structured_line(
raw: &str,
tasks: &[DiscoveredTask],
valid_subcommands: &HashSet<String>,
) -> Result<Option<AskSelection>> {
if let Some(rest) = raw.strip_prefix("task:") {
let task_name = extract_task_name(rest.trim(), tasks)?;
return Ok(Some(AskSelection::Task { name: task_name }));
}
if let Some(rest) = raw.strip_prefix("cmd:") {
let command = normalize_command(rest, valid_subcommands)?;
return Ok(Some(AskSelection::Command { command }));
}
if let Some(rest) = raw.strip_prefix("command:") {
let command = normalize_command(rest, valid_subcommands)?;
return Ok(Some(AskSelection::Command { command }));View on GitHub (pinned to a747e741ae)
Solutions
- Log the full offending response (it is embedded in the error) and tighten the prompt to demand exact formats
- Extend normalize_name-style fuzzy matching so near-miss task names still resolve
- Verify the task list sent to the model matches the discovered tasks (cache invalidation)
- Fallback to asking the user to pick manually instead of bailing
Example fix
// before
bail!("Could not parse AI response: '{}'", cleaned);
// after
bail!("Could not parse AI response: '{}'. Valid tasks: {:?}; subcommands: {:?}", cleaned, task_names, valid_subcommands); Defensive patterns
Strategy: fallback
Validate before calling
fn response_matches_known_shapes(response: &str, tasks: &[DiscoveredTask], subcommands: &HashSet<String>) -> bool {
let cleaned = response.trim().trim_matches('`').trim();
cleaned.starts_with("task:") || cleaned.starts_with("cmd:") || cleaned.starts_with("command:")
|| cleaned.starts_with("f ") || cleaned.starts_with("flow ")
|| tasks.iter().any(|t| t.task.name.eq_ignore_ascii_case(cleaned))
|| subcommands.contains(&cleaned.split_whitespace().next().unwrap_or("").to_ascii_lowercase())
} Try / catch
match parse_ask_response(&response, &tasks, &subcommands) {
Err(e) if e.to_string().starts_with("Could not parse AI response") => {
eprintln!("{}\nFalling back to manual selection.", e);
prompt_manual_selection(&tasks)
}
other => other,
} Prevention
- Include exact format instructions and the current task/subcommand list in the prompt
- Log the full AI reply when parsing fails (it's embedded in the error)
- Fuzzily match task names instead of exact-case matching
- Offer an interactive fallback instead of hard-failing
When it happens
Trigger: The model returns prose ('You could run the build task...'), an unknown/misnamed command ('f buil'), or a task name that doesn't match any discovered task case-insensitively.
Common situations: Weak model ignoring the response-format instructions; task list drifted (task renamed/removed since discovery); hallucinated subcommand not in cli_subcommands(); markdown formatting around the answer that wasn't fully stripped.
Related errors
- AI returned an empty response.
- Could not parse task name from AI response: '{}'
- No exchanges found in session
- Command '{}' is incomplete.
- AI returned unknown command '{}'.
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/11913f2a80cfb8f5.
Report an issue: GitHub.