-
-
Notifications
You must be signed in to change notification settings - Fork 69.4k
Billing/quota errors can be misclassified as context overflow #40378
Description
Bug Description
When an LLM provider (e.g., OpenRouter) returns a spend-limit or billing error, it can be misclassified as a "Context overflow" error, showing the user:
Context overflow: prompt too large for the model. Try /reset (or /new) to start a fresh session, or use a larger-context model.
...when the actual problem is that the API key hit its credit/spend limit.
Root Cause
The error classification in the catch block of the agent runner (in compact-*.js, around the runEmbeddedAgent flow) checks isLikelyContextOverflowError() before checking for billing errors. The billing detection (isBillingErrorMessage) only runs on assistant-level errors (structured responses), not on raw thrown exceptions in the catch path.
If the provider's error message contains patterns like "request size exceeds", "413 too large", or similar text that matches the context overflow regex, it gets classified as context overflow even though the underlying cause is a billing/quota limit.
Relevant code paths
isLikelyContextOverflowError()inpi-embedded-helpers— broad regex matching on error stringsisBillingErrorMessage()inpi-embedded-helpers— checks for "insufficient credits", HTTP 402, "payment required", etc.- Catch block in the agent runner (~line 56322 in
compact-*.js) — only checks context overflow, compaction failure, role ordering, transient HTTP, and session corruption. No billing check. - The assistant-level error path (~line 17961) does correctly detect billing via
isBillingAssistantError()and produces the right user-facing message.
Expected Behavior
Billing/quota errors should show the existing billing-specific message:
⚠️ [Provider] returned a billing error — your API key has run out of credits or has an insufficient balance. Check your [provider] billing dashboard and top up or switch to a different API key.
Suggested Fix
In the catch block, check isBillingErrorMessage(message) before isLikelyContextOverflowError(message), since billing is a more specific error class. Something like:
// In the catch block, before the existing context overflow check:
const isBilling = isBillingErrorMessage(message);
const isContextOverflow = !isBilling && isLikelyContextOverflowError(message);Then add a billing-specific return path similar to the existing context overflow one.
Environment
- OpenClaw: latest (as of 2026-03-08)
- Provider: OpenRouter (anthropic/claude-opus-4.6)
- Trigger: OpenRouter API key spend limit reached