thedotmack/claude-mem · error · ServerClassifiedProviderError
OpenRouter API error
Error message
OpenRouter API error: ${data.error.code} - ${data.error.message} What it means
The OpenRouter response parsed as JSON but contains an `error` object (OpenRouter's OpenAI-style error envelope), so the provider throws classifyHttpProviderError with cause `OpenRouter API error: <code> - <message>` and bodyText built from data.error.code/message. This surfaces provider-side errors delivered with a parseable body — often model-not-found, moderation, or upstream provider failures.
Solutions
- Read data.error.code/message in the cause: 'model_not_found' → use a valid slug; 402 → add credits; 429 → back off.
- Verify the model slug and account access on openrouter.ai.
- Retry with backoff only when the code indicates a transient/upstream failure.
- Fall back to an alternate provider/model for resilient generation.
Example fix
// before
const text = data.choices[0].message.content;
// after
if (data.error) throw new Error(`OpenRouter envelope: ${data.error.code} - ${data.error.message}`);
const text = data.choices?.[0]?.message?.content; Defensive patterns
Strategy: type-guard
Type guard
function hasErrorEnvelope<T extends { error?: { code?: string | number; message?: string } }>(data: T): boolean {
return data.error != null;
} Try / catch
try {
result = await openRouterProvider.generate(prompt, signal);
} catch (e) {
if (/model_not_found/.test(String(e.cause?.message))) return useFallbackModel();
if (e.kind === 'retryable') return retryWithBackoff();
throw e;
} Prevention
- Check data.error before reading data.choices.
- Validate model slugs and account access before shipping model IDs in config.
- Route on data.error.code: 429/5xx → backoff; model_not_found/402 → fix config or credits.
- Maintain a fallback model list for upstream provider failures.
When it happens
Trigger: Parsed JSON has `data.error` present with fields like code ('model_not_found', 402, 429) and message — thrown at OpenRouterObservationProvider.ts:114-121.
Common situations: Requesting a model slug the account cannot access, upstream LLM provider outage relayed by OpenRouter with 200-ish status via gateway, moderation/refusal envelopes, credits errors delivered in-body.
Related errors
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/340939e8c7b4cbf7.
Report an issue: GitHub.
Appendix: source
Thrown at src/server/generation/providers/OpenRouterObservationProvider.ts:117
headers: response.headers,
cause: new Error(`OpenRouter API error: ${response.status} - ${bodyText}`),
providerLabel: 'OpenRouter',
});
}
let data: OpenRouterResponse;
try {
data = (await response.json()) as OpenRouterResponse;
} catch (parseError) {
const err = parseError instanceof Error ? parseError : new Error(String(parseError));
throw new ServerClassifiedProviderError('OpenRouter returned invalid JSON', {
kind: 'parse_error',
cause: err,
});
}
if (data.error) {
throw classifyHttpProviderError({
status: response.status,
bodyText: `${data.error.code ?? ''} ${data.error.message ?? ''}`,
headers: response.headers,
cause: new Error(`OpenRouter API error: ${data.error.code} - ${data.error.message}`),
providerLabel: 'OpenRouter',
});
}
const rawText = data.choices?.[0]?.message?.content?.trim() ?? '';
if (!rawText) {
logger.warn('SDK', 'OpenRouter returned empty content', {
provider: 'openrouter',
model: this.model,
});
}
const tokensUsed = typeof data.usage?.total_tokens === 'number' ? data.usage.total_tokens : undefined;
View on GitHub (pinned to d8bc9755e7)