fix(classifier): treat Anthropic "out of extra usage" 400 as billing
Anthropic returns HTTP 400 with "You're out of extra usage. Add more at claude.ai/settings/usage and keep going." when the account's extra-usage allowance is depleted. The existing _BILLING_PATTERNS list did not include this wording, so classify_api_error fell through to generic format_error — non-retryable and should_fallback=False — causing the agent to abort instead of engaging the configured fallback chain. Add the pattern and a regression test covering the exact Anthropic body.
This commit is contained in:
parent
12556a9a77
commit
ea9e8d6e8c
2 changed files with 20 additions and 0 deletions
|
|
@ -110,6 +110,7 @@ _BILLING_PATTERNS = [
|
|||
"exceeded your current quota",
|
||||
"account is deactivated",
|
||||
"plan does not include",
|
||||
"out of extra usage", # Anthropic OAuth Pro/Max overage bucket depleted (HTTP 400)
|
||||
"out of funds",
|
||||
"run out of funds",
|
||||
"balance_depleted",
|
||||
|
|
|
|||
|
|
@ -1295,6 +1295,25 @@ class TestAdversarialEdgeCases:
|
|||
result = classify_api_error(e)
|
||||
assert result.reason == FailoverReason.billing
|
||||
|
||||
def test_400_anthropic_extra_usage_exhausted(self):
|
||||
"""Anthropic returns 400 with 'out of extra usage' when the user's
|
||||
extra-usage allowance is depleted. Must classify as billing so the
|
||||
fallback chain engages (with credential rotation) instead of the
|
||||
generic format_error path, which never rotates. (#11736, #13170)"""
|
||||
e = MockAPIError(
|
||||
"You're out of extra usage. Add more at claude.ai/settings/usage and keep going.",
|
||||
status_code=400,
|
||||
body={"error": {
|
||||
"type": "invalid_request_error",
|
||||
"message": "You're out of extra usage. Add more at claude.ai/settings/usage and keep going.",
|
||||
}},
|
||||
)
|
||||
result = classify_api_error(e, provider="anthropic")
|
||||
assert result.reason == FailoverReason.billing
|
||||
assert result.should_fallback is True
|
||||
assert result.retryable is False
|
||||
assert result.should_rotate_credential is True
|
||||
|
||||
def test_200_with_error_body(self):
|
||||
"""200 status with error in body — should be unknown, not crash."""
|
||||
class WeirdSuccess(Exception):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue