Repository navigation
fix(billing): show OpenRouter's routing reason when an EU key cannot serve the model - #1404
Conversation
…endpoint The EU instance sends every model call to eu.openrouter.ai, which only serves chat to Business or Enterprise plans. The save-time check called /key, which answers 200 for any live key, so a key on a lower plan saved fine and then every agent turn failed with a 403. On the EU instance, saving now also asks the in-region chat endpoint for one token: a 403 is refused with a message naming the plan requirement, a 402 as out of credits.
…ient
The key check now goes through two typed operations (getKey,
createChatCompletion) built on @distilled.cloud/core: a credentials service
resolved per request, a REST protocol reading OpenRouter's
{ error: { code, message } } body, and per-status error classes
(Unauthorized, PaymentRequired, Forbidden). The service maps those tags to
what the settings page shows instead of branching on raw status codes.
…/5xx - EU_DEFAULT_OPENROUTER_MODEL moves to @maple/domain/organization-regions; the agents and the EU key check both read it, so a model change cannot leave EU key saves failing on a model the catalogue dropped - Cover the EU check's 402 refusal and its retryable upstream failure
…serve the model An EU key on the right plan can still fail every turn when its own OpenRouter account settings remove the only in-region provider (e.g. an attached Azure provider key outside the EU: "Drop Out-of-Region Endpoints After BYOK removed azure/eu", a 404). The EU key check fell through to the generic NotFound and told the admin to try again, dropping OpenRouter's explanation. The OpenRouter client now types 400 and 404 on the chat completion, and the key check refuses those with OpenRouter's message and a pointer to the account's provider key and data region settings.
…u-routing-errors # Conflicts: # packages/backend/src/services/org/OrgOpenRouterKeyService.test.ts # packages/backend/src/services/org/OrgOpenRouterKeyService.ts # packages/backend/src/services/org/openrouter-api.ts
Maple review🟢 Confidence 9/10 · safe to merge Types OpenRouter's 400/404 on
Production impactOpen errors in the changed files
After this merges, Maple checks whether they stop. What was checked
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
Follow-up to #1401, which added the OpenRouter client and the EU key check.
Problem
A customer's EU key now passes the plan check, but every chat turn fails with a 404 from
eu.openrouter.ai:azure/euis the only EU provider for the EU default model. It was removed by a setting in the customer's own OpenRouter account: OpenRouter's wording points to a provider key attached to that account whose Azure resource is outside the EU. The EU key check sees this 404 as an untypedNotFoundand tells the admin "Could not check this key with OpenRouter (NotFound). Try again." That message is wrong, because retrying fails the same way every time, and it drops the one line that explains what to change.Change
openrouter-api.ts:createChatCompletionnow has typedBadRequest(400) andNotFound(404) errors, and both keep OpenRouter's message.OrgOpenRouterKeyService:toKeyErrorrefuses a save that fails with either as a key problem (OpenRouterKeyValidationError). The admin sees OpenRouter's reason, followed by a pointer to the provider key and data region settings in their OpenRouter account.Only the EU check makes a chat call, so US saves are unchanged. A key that is already saved isn't re-checked: the affected org has to fix its OpenRouter settings, or re-save its key to see the reason.
Tests
A new case gives the EU check a 404 with OpenRouter's
{ error: { code, message } }body. It asserts that the save is refused, that OpenRouter's reason is in the message, and that nothing is stored.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by CodeRabbit