{"record":{"id":"5826921324019c9d","repo":"nikivdev/code","slug":"openrouter-returned-empty-commit-message","errorCode":null,"errorMessage":"OpenRouter returned empty commit message","messagePattern":"OpenRouter returned empty commit message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/commit.rs","lineNumber":12879,"sourceCode":"                role: \"user\".to_string(),\n                content: user_prompt,\n            },\n        ],\n        temperature: 0.3,\n    };\n\n    let parsed: ChatResponse = openrouter_chat_completion_with_retry(&client, &api_key, &body)\n        .context(\"OpenRouter request failed\")?;\n\n    let message = parsed\n        .choices\n        .first()\n        .and_then(|c| c.message.as_ref())\n        .map(|m| m.content.trim().to_string())\n        .unwrap_or_default();\n\n    if message.is_empty() {\n        bail!(\"OpenRouter returned empty commit message\");\n    }\n\n    Ok(trim_quotes(&message))\n}\n\nfn generate_commit_message(\n    api_key: &str,\n    diff: &str,\n    status: &str,\n    truncated: bool,\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 to fit within prompt]\");\n    }","sourceCodeStart":12861,"sourceCodeEnd":12897,"githubUrl":"https://github.com/nikivdev/code/blob/a747e741ae92c09071d0ae946ab48488adcff1ce/src/commit.rs#L12861-L12897","documentation":"Thrown when the OpenRouter API returned HTTP success but the first choice's message content is empty or absent, so the default `unwrap_or_default()` yields an empty string.","triggerScenarios":"OpenRouter responds 200 with `choices[0].message.content` missing, null, or whitespace-only — e.g. the routed model returned an empty completion, a content-filter stop, or an unexpected response shape.","commonSituations":"Selected OpenRouter model is deprecated/degraded; content filter suppressed the output; large diff prompt hit a token limit causing truncated/empty output; API schema change not reflected in the `ChatResponse` struct.","solutions":["Retry with a different OpenRouter model to rule out a degraded model.","Reduce the diff/prompt size to stay within the model's context window.","Log the raw JSON response and check `finish_reason` (content_filter, length) and confirm `choices[0].message.content` is populated.","Verify the `ChatResponse` struct still matches OpenRouter's current API schema."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Validate model id is configured before calling OpenRouter\nif model_id.is_empty() {\n    return Err(anyhow!(\"OpenRouter model id must be set\"));\n}","typeGuard":"fn openrouter_choice_has_content(resp: &ChatResponse) -> bool {\n    resp.choices.first()\n        .and_then(|c| c.message.as_ref())\n        .map(|m| !m.content.trim().is_empty())\n        .unwrap_or(false)\n}","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"OpenRouter returned empty\") => {\n        eprintln!(\"OpenRouter gave empty content; retrying with another model\");\n        fallback_to_alternate_model()\n    }\n    other => other,\n}","preventionTips":["Keep the configured OpenRouter model id current (models get deprecated).","Check `finish_reason` in raw responses for content_filter/length stops.","Limit diff size to fit the model's context window.","Configure model fallback chains in settings."],"tags":["ai","api","empty-output","openrouter"],"backgroundTag":"ai-empty-response","analyzedSha":"a747e741ae92c09071d0ae946ab48488adcff1ce","analyzedAt":"2026-09-01T22:43:55.719Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}