diff --git a/agent/auxiliary_client.py b/agent/auxiliary_client.py index 0afb0add20b..18a6f9bfa73 100644 --- a/agent/auxiliary_client.py +++ b/agent/auxiliary_client.py @@ -2470,7 +2470,7 @@ def _is_payment_error(exc: Exception) -> bool: # but sometimes wrap them in 429 or other codes. # Daily quota exhaustion from Bedrock, Vertex AI, and similar providers # uses different language but is semantically identical to credit exhaustion. - if status in {402, 404, 429, None}: + if status in {402, 403, 404, 429, None}: if any(kw in err_lower for kw in ( "credits", "insufficient funds", "can only afford", "billing", @@ -2479,6 +2479,8 @@ def _is_payment_error(exc: Exception) -> bool: "balance_depleted", "no usable credits", "model_not_supported_on_free_tier", "not available on the free tier", + "requires a subscription", "upgrade for access", + "upgrade for higher limits", "reached your session usage limit", # Daily / monthly / weekly quota exhaustion keywords "quota exceeded", "quota_exceeded", "too many tokens per day", "daily limit", diff --git a/tests/agent/test_auxiliary_client.py b/tests/agent/test_auxiliary_client.py index dac9956b494..060a817998e 100644 --- a/tests/agent/test_auxiliary_client.py +++ b/tests/agent/test_auxiliary_client.py @@ -1406,6 +1406,21 @@ class TestIsPaymentError: exc.status_code = 404 assert _is_payment_error(exc) is True + def test_403_subscription_required_is_payment(self): + exc = Exception( + "this model requires a subscription, upgrade for access: " + "https://ollama.com/upgrade" + ) + setattr(exc, "status_code", 403) + assert _is_payment_error(exc) is True + + def test_429_session_usage_limit_is_payment(self): + exc = Exception( + "you have reached your session usage limit, upgrade for higher limits" + ) + setattr(exc, "status_code", 429) + assert _is_payment_error(exc) is True + def test_404_generic_not_found_is_not_payment(self): exc = Exception("Not Found") exc.status_code = 404