Mintplex-Labs/anything-llm · error · Error
Invalid response body returned from OpenRouter: ${result.out
Error message
Invalid response body returned from OpenRouter: ${result.output?.error?.message || "Unknown error"} ${result.output?.error?.code || "Unknown code"} What it means
Post-success structural validation: the chat.completions.create call resolved without throwing, but the body lacks a 'choices' array (or it is empty). OpenRouter sometimes returns 200 with an inline error object; the message includes result.output.error.message and result.output.error.code when present. This is the catch for shape problems the SDK did not reject on.
Source
Thrown at server/utils/AiProviders/openRouter/index.js:267
.create({
model: this.model,
messages,
temperature,
// This is an OpenRouter specific option that allows us to get the reasoning text
// before the token text.
include_reasoning: true,
user: user?.id ? `user_${user.id}` : "",
})
.catch((e) => {
throw new Error(e.message);
})
);
if (
!result?.output?.hasOwnProperty("choices") ||
result?.output?.choices?.length === 0
)
throw new Error(
`Invalid response body returned from OpenRouter: ${result.output?.error?.message || "Unknown error"} ${result.output?.error?.code || "Unknown code"}`
);
return {
textResponse: this.#parseReasoningFromResponse(result.output.choices[0]),
metrics: {
prompt_tokens: result.output.usage.prompt_tokens || 0,
completion_tokens: result.output.usage.completion_tokens || 0,
total_tokens: result.output.usage.total_tokens || 0,
outputTps: result.output.usage.completion_tokens / result.duration,
duration: result.duration,
model: this.model,
provider: this.className,
timestamp: new Date(),
},
};
}
View on GitHub (pinned to 526360e320)
Solutions
- Inspect the embedded error.message/error.code in the thrown text for the upstream cause.
- Retry once — many of these are transient upstream blips.
- Switch to a different model/provider slug for the same capability.
- Check OpenRouter status (status.openrouter.ai) for provider outages.
Example fix
// before
if (!result?.output?.hasOwnProperty('choices') || result?.output?.choices?.length === 0)
throw new Error(`Invalid response body returned from OpenRouter: ${result.output?.error?.message || 'Unknown error'} ${result.output?.error?.code || 'Unknown code'}`);
// after - treat upstream errors as retryable signals with a code
const body = result?.output;
if (!body?.hasOwnProperty('choices') || body?.choices?.length === 0) {
const err = new Error(`OpenRouter returned no choices: ${body?.error?.message || 'Unknown error'} (${body?.error?.code || 'Unknown code'})`);
err.code = body?.error?.code || 'NO_CHOICES';
err.retryable = true;
throw err;
} Defensive patterns
Strategy: fallback
Validate before calling
const hasOpenRouterChoices = (o) => !!o && typeof o === 'object' && Array.isArray(o.choices) && o.choices.length > 0;
Type guard
const hasOpenRouterChoices = (o) => !!o && typeof o === 'object' && Array.isArray(o.choices) && o.choices.length > 0;
Try / catch
try {
const r = await llm.getChatCompletion(messages, { temperature });
return r;
} catch (e) {
if (e.message.startsWith('Invalid response body returned from OpenRouter'))
return fallbackResponse(); // upstream 200-with-error; retry or degrade
throw e;
} Prevention
- Treat a 200-with-no-choices as a transient upstream signal and retry once before degrading.
- Surface result.output.error.code so callers can distinguish content-filter from provider outage.
- Keep a fallback model/provider for cases where the primary returns empty bodies.
When it happens
Trigger: OpenRouter forwards an upstream error as HTTP 200 with an error body (no choices); empty choices array from a content filter; response schema drift; provider returned only usage/metadata with no completion; rate-limit-style body that the SDK treated as success.
Common situations: Upstream provider errored and OpenRouter wrapped it as 200-with-error; content policy produced zero choices; transient provider hiccup; model returns tool-call-only with no text choices; partial outage where OpenRouter returns metadata but no content.
Related errors
- ${e.message}
- Ollama::getChatCompletion failed to communicate with Ollama.
- ${e.message}
- ${e.message}
- ${e.message}
AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13).
Data as JSON: /api/errors/5ad39777a0959d6a.
Report an issue: GitHub.