You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(fal): classify 403 balance-exhausted as insufficient_balance, not auth_failure
When a fal (fal.ai) account runs out of credit, fal returns HTTP 403 with a
body like `{"detail":"User is locked. Reason: TOP_UP."}` or "...Reason:
Exhausted balance. Top up your balance at fal.ai/dashboard/billing.".
The fal adapter previously classified ALL 401/403 as
Scope=ScopeKey / Reason=auth_failure, which maps to a fixed 1-hour
provider-level cooldown (the "bad key, needs human intervention" policy).
That is wrong for an out-of-credit state: the key is valid and recovery is
self-service — after a top-up the account works again immediately, yet maxx
kept the provider cooled for up to an hour.
Fix: detect the billing/lock case in the fal doJSON error classifier — a 403
(or 402) whose `detail` matches billing signals (TOP_UP / "Exhausted balance"
/ "User is locked" / "top up" / insufficient / balance, case-insensitive) —
and classify it with a new dedicated CooldownReasonInsufficientBalance. It
stays ScopeKey and non-retryable (retrying now won't help), but maps to a
short fixed 2-minute cooldown so the provider recovers promptly post top-up,
and the reason string in logs/DB is now "insufficient_balance" instead of the
misleading "auth_failure". Genuine auth failures (401 always; 403 without
billing signals) remain auth_failure / 1h as before.
Adds the CooldownReason enum value in both canonical places (domain and the
cooldown policy package) plus its 2m FixedDurationPolicy, and focused tests
in the fal package (403 TOP_UP/Exhausted vs 401 / plain 403) and the cooldown
package (new reason maps short, shorter than auth_failure).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0 commit comments