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

  1. Log the full offending response (it is embedded in the error) and tighten the prompt to demand exact formats
  2. Extend normalize_name-style fuzzy matching so near-miss task names still resolve
  3. Verify the task list sent to the model matches the discovered tasks (cache invalidation)
  4. 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

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