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

  1. Read data.error.code/message in the cause: 'model_not_found' → use a valid slug; 402 → add credits; 429 → back off.
  2. Verify the model slug and account access on openrouter.ai.
  3. Retry with backoff only when the code indicates a transient/upstream failure.
  4. 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

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)