{"record":{"id":"0becb6d2f9c80075","repo":"nikivdev/code","slug":"ai-returned-unknown-command","errorCode":null,"errorMessage":"AI returned unknown command '{}'.","messagePattern":"AI returned unknown command '(.+?)'\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/ask.rs","lineNumber":505,"sourceCode":"        cmd = cmd.trim_start_matches(\"cmd:\").trim().to_string();\n    } else if cmd.starts_with(\"command:\") {\n        cmd = cmd.trim_start_matches(\"command:\").trim().to_string();\n    }\n\n    if cmd.starts_with(\"flow \") {\n        cmd = format!(\"f {}\", cmd.trim_start_matches(\"flow \").trim());\n    } else if !cmd.starts_with(\"f \") {\n        cmd = format!(\"f {}\", cmd);\n    }\n\n    let tokens = shell_words::split(&cmd)\n        .unwrap_or_else(|_| cmd.split_whitespace().map(|s| s.to_string()).collect());\n    if tokens.len() < 2 {\n        bail!(\"Command '{}' is incomplete.\", cmd);\n    }\n    let sub = tokens[1].to_ascii_lowercase();\n    if !valid_subcommands.contains(&sub) {\n        bail!(\"AI returned unknown command '{}'.\", cmd);\n    }\n\n    Ok(cmd)\n}\n\nfn is_command_like(raw: &str, valid_subcommands: &HashSet<String>) -> bool {\n    let first = raw\n        .split_whitespace()\n        .next()\n        .unwrap_or(\"\")\n        .trim()\n        .to_ascii_lowercase();\n    if first.is_empty() {\n        return false;\n    }\n    valid_subcommands.contains(&first)\n}\n","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/ask.rs#L487-L523","documentation":"After tokenizing the suggestion, normalize_command lowercases tokens[1] and checks it against the set of valid subcommands (from clap's Cli). If the subcommand the AI produced is not a known subcommand or alias, the command would fail downstream, so it's rejected here with the full command in the message.","triggerScenarios":"The AI hallucinates a subcommand ('f deploy-prod' when only 'deploy' exists), invents flags-as-subcommands, or uses a name from a different CLI version.","commonSituations":"Model trained on an older/newer CLI surface; task list vs CLI subcommand confusion; case-sensitivity handled but hyphen/underscore variants not in valid_subcommands; suggestion generated from stale help text.","solutions":["Compare the message's command against `f --help` output and correct the subcommand name manually","Improve the prompt by injecting the exact current subcommand list and forbidding others","Add fuzzy/alias matching in normalize_command (e.g. normalize_name-style comparison) before rejecting","Fall back to re-asking the AI or presenting an interactive subcommand picker"],"exampleFix":"// before\nlet sub = tokens[1].to_ascii_lowercase();\nif !valid_subcommands.contains(&sub) {\n    bail!(\"AI returned unknown command '{}'.\", cmd);\n}\n// after\nlet sub = tokens[1].to_ascii_lowercase();\nif !valid_subcommands.contains(&sub) {\n    if let Some(matched) = valid_subcommands.iter().find(|v| normalize_name(v) == normalize_name(&sub)) {\n        tokens[1] = matched.clone();\n        return Ok(tokens.join(\" \"));\n    }\n    bail!(\"AI returned unknown command '{}'. Valid subcommands: {:?}\", cmd, valid_subcommands);\n}","handlingStrategy":"validation","validationCode":"fn suggestion_subcommand_is_valid(raw: &str, valid: &HashSet<String>) -> bool {\n    let tokens: Vec<String> = raw.split_whitespace().map(|s| s.to_string()).collect();\n    tokens.get(1).map(|t| valid.contains(&t.to_ascii_lowercase())).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match normalize_command(raw, &valid_subcommands) {\n    Err(e) if e.to_string().contains(\"unknown command\") => {\n        eprintln!(\"{}\\nRun `f --help` for valid subcommands.\", e);\n    }\n    other => other,\n}","preventionTips":["Inject the exact current subcommand list into the AI prompt","Keep CLI aliases registered so clap-derived valid_subcommands covers them","Add fuzzy/normalized matching before rejecting near-miss names","Re-validate suggestions whenever the CLI surface changes between versions"],"tags":["cli","validation","llm-output"],"backgroundTag":"unknown-subcommand","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}