{"record":{"id":"6e31b0bc5e39129d","repo":"nikivdev/code","slug":"claude-returned-empty-commit-message","errorCode":null,"errorMessage":"claude returned empty commit message","messagePattern":"claude returned empty commit message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/commit.rs","lineNumber":12762,"sourceCode":"    if !status.is_empty() {\n        prompt.push_str(\"\\n\\nGit status:\\n\");\n        prompt.push_str(status);\n    }\n\n    let output = Command::new(\"claude\")\n        .args([\"-p\", &prompt])\n        .output()\n        .context(\"failed to run claude for commit message\")?;\n\n    if !output.status.success() {\n        let stderr = String::from_utf8_lossy(&output.stderr);\n        bail!(\"claude failed: {}\", stderr.trim());\n    }\n\n    let message = String::from_utf8_lossy(&output.stdout).trim().to_string();\n\n    if message.is_empty() {\n        bail!(\"claude returned empty commit message\");\n    }\n\n    Ok(trim_quotes(&message))\n}\n\n/// Generate commit message using Rise daemon (local AI proxy).\nfn generate_commit_message_rise(\n    diff: &str,\n    status: &str,\n    truncated: bool,\n    model: &str,\n) -> Result<String> {\n    let mut user_prompt =\n        String::from(\"Write a git commit message for the staged changes.\\n\\nGit diff:\\n\");\n    user_prompt.push_str(diff);\n\n    if truncated {\n        user_prompt.push_str(\"\\n\\n[Diff truncated]\");","sourceCodeStart":12744,"sourceCodeEnd":12780,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/commit.rs#L12744-L12780","documentation":"Thrown when the `claude` CLI exits successfully but its stdout, after trimming, is empty — no commit message was produced. The code deliberately distinguishes this from a process failure to give a clearer message.","triggerScenarios":"`claude -p <prompt>` exits 0 but prints nothing: silent auth degradation, output redirected elsewhere, model refusal producing no text, or stdout swallowed by a wrapper/alias.","commonSituations":"A shell alias or wrapper around `claude` consumes stdout; claude session expired so it warns on stderr but exits 0; model returns an empty response on a very large diff prompt.","solutions":["Run `claude -p \"say hi\"` and confirm it prints text to stdout.","Re-authenticate with `claude login`.","Check for shell aliases/wrappers intercepting claude output (`type claude`).","Retry with a smaller diff/staged change set in case the model returned empty on a huge prompt."],"exampleFix":"// before\nif message.is_empty() {\n    bail!(\"claude returned empty commit message\");\n}\n// after\nif message.is_empty() {\n    bail!(\"claude returned empty commit message (stderr: {})\", String::from_utf8_lossy(&output.stderr).trim());\n}","handlingStrategy":"fallback","validationCode":"// Preflight: confirm claude produces non-empty stdout\nlet out = std::process::Command::new(\"claude\").args([\"-p\", \"ping\"]).output()?;\nif String::from_utf8_lossy(&out.stdout).trim().is_empty() {\n    return Err(anyhow!(\"claude CLI produces empty output\"));\n}","typeGuard":"fn is_non_empty_message(s: &str) -> bool { !s.trim().is_empty() }","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"empty commit message\") => {\n        eprintln!(\"claude returned nothing; check auth/alias, falling back\");\n        fallback_to_manual_message()\n    }\n    other => other,\n}","preventionTips":["Avoid shell aliases/wrappers around `claude` that swallow stdout.","Re-authenticate when stderr shows warnings but exit code is 0.","Cap diff size in the prompt so the model doesn't return empty on huge inputs.","Configure a fallback provider for empty responses."],"tags":["cli","ai","empty-output"],"backgroundTag":"ai-empty-response","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}