nikivdev/code · error
OpenRouter returned empty review output
Error message
OpenRouter returned empty review output
What it means
The AI code-review feature calls OpenRouter's chat-completions API and expects a non-empty assistant message. After the HTTP request succeeds, the tool extracts choices[0].message.content, trims it, and throws this error if the result is an empty string. It means OpenRouter returned a 200 response whose payload contained no usable text.
Source
Thrown at src/commit.rs:6217
let start = std::time::Instant::now();
let parsed: ChatResponse = openrouter_chat_completion_with_retry(&client, &api_key, &body)
.context("OpenRouter request failed")?;
info!(
elapsed_ms = start.elapsed().as_millis() as u64,
"OpenRouter responded"
);
let output = parsed
.choices
.first()
.and_then(|c| c.message.as_ref())
.map(|m| m.content.trim().to_string())
.unwrap_or_default();
if output.is_empty() {
bail!("OpenRouter returned empty review output");
}
println!("{}", output);
let mut review_json = parse_review_json(&output);
let future_tasks = review_json
.as_ref()
.map(|json| normalize_future_tasks(&json.future_tasks))
.unwrap_or_default();
let mut summary = review_json.as_ref().and_then(|r| r.summary.clone());
let quality = review_json.as_mut().and_then(|r| r.quality.take());
let (mut issues_found, mut issues) = if let Some(ref json) = review_json {
(json.issues_found, json.issues.clone())
} else {
let lowered = output.to_lowercase();
let has_issues = lowered.contains("bug")
|| lowered.contains("issue")
|| lowered.contains("error")View on GitHub (pinned to a747e741ae)
Solutions
- Re-run the review; transient empty completions often succeed on retry
- Switch to a different/more capable model via the model config
- Verify the OpenRouter API key and account quota at openrouter.ai
- Log the raw response body to confirm whether choices/content are missing
- Reduce the diff size sent in the prompt so the model can produce output
Example fix
// before
let output = parsed.choices.first()
.and_then(|c| c.message.as_ref())
.map(|m| m.content.trim().to_string())
.unwrap_or_default();
if output.is_empty() { bail!("OpenRouter returned empty review output"); }
// after
let output = parsed.choices.first()
.and_then(|c| c.message.as_ref())
.map(|m| m.content.trim().to_string())
.unwrap_or_default();
let output = if output.is_empty() {
eprintln!("empty review output; retrying once");
retry_request(&client, &api_key, &body)?
} else { output }; Defensive patterns
Strategy: retry
Validate before calling
let body = serde_json::to_string(&request)?;
// after the response:
let text = parsed.choices.first()
.and_then(|c| c.message.as_ref())
.map(|m| m.content.trim().to_string())
.unwrap_or_default();
if text.is_empty() { eprintln!("warning: empty model output; will retry"); } Type guard
fn non_empty_review(resp: &ChatResponse) -> Option<&str> {
resp.choices.first()
.and_then(|c| c.message.as_ref())
.map(|m| m.content.trim())
.filter(|s| !s.is_empty())
} Try / catch
match run_review() {
Err(e) if e.to_string().contains("empty review output") => {
eprintln!("model returned nothing; retrying with different model");
run_review_with_fallback_model()?;
}
Err(e) => return Err(e),
Ok(v) => v,
} Prevention
- Pick a reliable review model with non-trivial max output tokens
- Keep prompts/diffs under model context limits
- Log raw OpenRouter response bodies for diagnosis
- Implement one automatic retry on empty output
- Monitor OpenRouter provider status/incidents
When it happens
Trigger: Calling the commit review flow when OpenRouter returns a response with an empty choices array, a choice with no message object, or message.content that is whitespace-only (e.g. model produced a refusal or empty completion).
Common situations: Weak or degraded model selected (empty completions), prompt too large so the model returns nothing, provider-side moderation blocking output, malformed/missing API response fields, or a model that outputs only tool-call/refusal content.
Related errors
- AI returned an empty response.
- OpenRouter returned empty commit message
- Could not parse AI response: '{}'
- Could not parse task name from AI response: '{}'
- device auth start failed: HTTP {}
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/94e20b960d4ba153.
Report an issue: GitHub.