rohitg00/agentmemory · error · Error

${this.name} API error (${response.status}): ${text}

Error message

${this.name} API error (${response.status}): ${text}

What it means

OpenRouterProvider.call throws `${this.name} API error (${status}): ${text}` for any non-2xx OpenRouter response, embedding the provider display name and the raw body. OpenRouter errors carry detail in the body — invalid key, no credits, model not found, or upstream model provider failure — so the appended text is the primary diagnostic.

Source

Thrown at src/providers/openrouter.ts:57

        "Content-Type": "application/json",
        Authorization: `Bearer ${this.apiKey}`,
        ...(this.baseUrl.includes("openrouter")
          ? { "HTTP-Referer": "https://github.com/rohitg00/agentmemory" }
          : {}),
      },
      body: JSON.stringify({
        model: this.model,
        max_tokens: this.maxTokens,
        messages: [
          { role: "system", content: systemPrompt },
          { role: "user", content: userPrompt },
        ],
      }),
    });

    if (!response.ok) {
      const text = await response.text();
      throw new Error(`${this.name} API error (${response.status}): ${text}`);
    }

    const data = (await response.json()) as Record<string, unknown>;
    const choices = data.choices as
      | Array<{ message: { content: string } }>
      | undefined;
    const content = choices?.[0]?.message?.content;
    if (!content) {
      throw new Error(
        `${this.name} returned unexpected response: ${JSON.stringify(data).slice(0, 200)}`,
      );
    }
    return content;
  }
}

View on GitHub (pinned to e04ba88819)

Solutions

  1. Read the appended body text — OpenRouter returns JSON with the exact error metadata
  2. If 402/401: add credits or fix the OpenRouter API key
  3. If 404: update config.model to a current OpenRouter model slug (check openrouter.ai/models)
  4. If 429: back off and retry, or switch to a less-rate-limited model/provider
  5. Wrap with the resilient provider so the circuit breaker and fallbacks absorb transient 5xx

Example fix

// before
model: 'anthropic/claude-3-sonnet' // 404: no endpoints found matching that model

// after
model: 'anthropic/claude-3.5-sonnet'
Defensive patterns

Strategy: retry

Validate before calling

if (!process.env.OPENROUTER_API_KEY) throw new Error('OPENROUTER_API_KEY not set');
if (!config.model?.includes('/')) throw new Error(`Model must be a vendor/slug pair, got: ${config.model}`);

Try / catch

try {
  return await provider.call(prompt);
} catch (e) {
  const m = /API error \((\d+)\)/.exec(String(e));
  const status = m ? Number(m[1]) : 0;
  if (status === 429 || status >= 500) return retryWithBackoff(() => provider.call(prompt), 3);
  if (status === 402) throw new Error('OpenRouter credits exhausted', { cause: e });
  throw e;
}

Prevention

When it happens

Trigger: compress()/summarize() via OpenRouterProvider.call() where response.ok is false: bad OPENROUTER_API_KEY (401), exhausted OpenRouter credits (402), unknown model slug in config.model (404), OpenRouter rate limit (429), or upstream provider error (502).

Common situations: Running out of OpenRouter credits mid-month; using a stale model slug after OpenRouter deprecates ':free' variants; key restricted to certain models by allowed-models policy; upstream model provider (e.g. a free backend) being temporarily down.

Related errors


AI-assisted analysis of rohitg00/agentmemory@e04ba88819 (2026-08-30). Data as JSON: /api/errors/33442e67bff8b813. Report an issue: GitHub.