Provider free-tier exhausted
When you shop around providers at the prototype stage, each has its own trial
credits — and they run out silently. From the outside it looks like “the model
suddenly stopped answering”: the code fails with insufficient_quota or
402 Payment Required, and you spend half an hour thinking you broke the prompt.
Separate this error from ordinary failures and send a push exactly once — with the name of the provider that ran out.
Catch specifically “quota exhausted”, not any error
Section titled “Catch specifically “quota exhausted”, not any error”It’s important not to confuse “credits ran out” (fixed by topping up) with 429 (fixed by waiting). For providers these are different codes/types — we check precisely.
import os, requestsimport openai, anthropic
NOTIFLY_URL = os.environ["NOTIFLY_URL"]NOTIFLY_TOKEN = os.environ["NOTIFLY_TOKEN"]
def notify(title, msg, prio): requests.post(f"{NOTIFLY_URL}/message", params={"token": NOTIFLY_TOKEN}, json={"title": title, "message": msg, "priority": prio}, timeout=5)
def _alerted_once(provider): """Per-provider flag: the exhausted-trial alert is sent once.""" flag = f"/tmp/free-tier-{provider}.flag" if os.path.exists(flag): return True open(flag, "w").close() return False
def is_quota_exhausted(exc): """True only for "credits/quota ran out", not for rate-limit.""" # OpenAI: 429 with code == "insufficient_quota" (yes, the same status as rate-limit) if isinstance(exc, openai.RateLimitError): code = (getattr(exc, "code", None) or (exc.body or {}).get("code") if getattr(exc, "body", None) else None) return code == "insufficient_quota" # Anthropic and many OpenAI-compatible APIs: 402 Payment Required status = getattr(exc, "status_code", None) return status == 402
def guard(provider, call): """Run the call; on quota exhaustion — push once and re-raise.""" try: return call() except Exception as e: if is_quota_exhausted(e) and not _alerted_once(provider): notify( f"🪙 {provider}: кончился free-tier", f"Ошибка квоты у {provider}. Пополните счёт или переключите провайдера.", priority=7, ) raise
# usageoai = openai.OpenAI()resp = guard("openai", lambda: oai.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": "ping"}]))OpenAI’s insufficient_quota arrives under the same status 429 as
rate-limit — so looking at the HTTP code alone isn’t enough, you need the
code. A per-provider flag file guarantees that after topping up you won’t
get the same alert a hundred times in a row.
Handy when shopping around providers
Section titled “Handy when shopping around providers”If you run the same prompt across several APIs at once, wrap each in its own
guard(provider, ...) — and the very first push tells you exactly whose credits
ran out, without digging through logs. After topping up, delete the flag file
(rm /tmp/free-tier-openai.flag) so the alert becomes possible again.
What to put in the alert text
Section titled “What to put in the alert text”- the provider name and model;
- the exact error code (
insufficient_quota/402) — to tell it apart from 429; - a direct link to that provider’s billing page;
- a reminder to delete the flag file after topping up.