{"record":{"id":"eb6ad4951e4ed309","repo":"sigoden/aichat","slug":"no-command-generated","errorCode":null,"errorMessage":"No command generated","messagePattern":"No command generated","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main.rs","lineNumber":256,"sourceCode":"}\n\n#[async_recursion::async_recursion]\nasync fn shell_execute(\n    config: &GlobalConfig,\n    shell: &Shell,\n    mut input: Input,\n    abort_signal: AbortSignal,\n) -> Result<()> {\n    let client = input.create_client()?;\n    config.write().before_chat_completion(&input)?;\n    let (eval_str, _) =\n        call_chat_completions(&input, false, true, client.as_ref(), abort_signal.clone()).await?;\n\n    config\n        .write()\n        .after_chat_completion(&input, &eval_str, &[])?;\n    if eval_str.is_empty() {\n        bail!(\"No command generated\");\n    }\n    if config.read().dry_run {\n        config.read().print_markdown(&eval_str)?;\n        return Ok(());\n    }\n    if *IS_STDOUT_TERMINAL {\n        let options = [\"execute\", \"revise\", \"describe\", \"copy\", \"quit\"];\n        let command = color_text(eval_str.trim(), nu_ansi_term::Color::Rgb(255, 165, 0));\n        let first_letter_color = nu_ansi_term::Color::Cyan;\n        let prompt_text = options\n            .iter()\n            .map(|v| format!(\"{}{}\", color_text(&v[0..1], first_letter_color), &v[1..]))\n            .collect::<Vec<String>>()\n            .join(&dimmed_text(\" | \"));\n        loop {\n            println!(\"{command}\");\n            let answer_char =\n                read_single_key(&['e', 'r', 'd', 'c', 'q'], 'e', &format!(\"{prompt_text}: \"))?;","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/sigoden/aichat/blob/82976d349ad97ac9aae0655ad631dace5e2a6385/src/main.rs#L238-L274","documentation":"Fires in shell_execute after the model's chat completion returns an empty evaluation string. Since the entire purpose of the call is to produce a shell command, an empty response means the LLM failed to generate anything executable, so the flow aborts before running a blank command.","triggerScenarios":"`call_chat_completions` returns an empty string after the after_chat_completion hook — e.g. the model replied with only whitespace or the response was filtered.","commonSituations":"Model refuses or returns an empty answer for an ambiguous prompt; overly strict system prompt suppresses output; a provider outage yields an empty completion.","solutions":["Rephrase the prompt so the model produces an actual command","Retry the request (transient empty completions)","Check the provider response — empty completions may indicate an API/model issue","Verify `after_chat_completion` hooks aren't stripping the output"],"exampleFix":"// before\nshell: \"\"\n// after\nshell: \"list all png files larger than 1MB in /tmp\"","handlingStrategy":"validation","validationCode":"if prompt.trim().is_empty() {\n    eprintln!(\"provide a non-empty shell task description\");\n}","typeGuard":null,"tryCatchPattern":"match shell_execute(...).await {\n    Err(e) if e.to_string() == \"No command generated\" => {\n        eprintln!(\"Model returned empty output; retry or rephrase prompt\");\n    }\n    other => other?,\n}","preventionTips":["Write specific, imperative prompts for shell generation","Retry once on empty completions (often transient)","Verify no after_chat_completion hook is stripping the response"],"tags":["llm","shell","empty-output"],"backgroundTag":"empty-response-body","analyzedSha":"82976d349ad97ac9aae0655ad631dace5e2a6385","analyzedAt":"2026-09-09T18:33:06.139Z","contentChangedAt":"2026-09-09T18:33:06.139Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}