429 enforced_spend_limit_reached: why retrying never works
A 429 with no retry-after can be a monthly spend cap, not a rate limit. What Anthropic's page says, and how Sume separates 402, 429 rate_limited and queue_full.

A 429 with no retry-after header can be a spend cap rather than a rate limit. Anthropic's rate-limit page says that once an organization reaches its monthly cap, requests return HTTP 429 with error_code enforced_spend_limit_reached, and retrying, including SDK automatic retries, fails until access resumes. Sume reports an empty balance as 402 insufficient_credits instead.
Anthropic facts are from its Rate limits page (cited under Sources) and Sume facts from Errors and rate limits, both read 2026-09-30.
How do I tell a spend cap from a rate limit?
Look for the header and the code. Anthropic's page lists the monthly caps by tier (Start $500 USD, Build $1,000 USD, Scale $200,000 USD) and says the cap response has no retry-after header, while an ordinary rate-limit 429 carries one.
| Situation | Status and code | Retry-after |
|---|---|---|
| Anthropic: rate limit exceeded | 429 | Sent |
| Anthropic: monthly spend cap reached | 429, enforced_spend_limit_reached | Not sent |
| Sume: request rate exceeded | 429 rate_limited | Use it when present |
| Sume: queue capacity full | 429 queue_full | Use it when present |
| Sume: balance too low | 402 insufficient_credits | Not a wait |
What does Sume return when the money runs out?
Sume returns 402 insufficient_credits before provider work starts, when it cannot reserve the estimated cost from the workspace balance. The docs list the next action as upgrading the plan, waiting for included Gen$, or submitting a cheaper request, and the quota job error category says to add funds or lower the request cost. Waiting does not fix it, so a 402 is not a retry case.
Sume keeps the 429s for two other things: rate_limited for request volume, and queue_full when the workspace has no accepted generation capacity left. Both clear as time passes or jobs finish.
What should a retry loop do with each one?
Retry a 429 only when it carries retry-after, and never retry a 402. For paid submits, reuse the same Idempotency-Key on every retry so a repeat cannot bill twice.
def should_retry(status: int, headers: dict, error_code: str) -> bool:
if status == 402:
return False # insufficient_credits: fund the wallet first
if status == 429:
return "retry-after" in headers # a cap has none
return False
print(should_retry(429, {"retry-after": "12"}, "rate_limited"))
print(should_retry(429, {}, "enforced_spend_limit_reached"))
print(should_retry(402, {}, "insufficient_credits"))What are the limits of this comparison?
The caps and tiers above are Anthropic's on the day read; check its page before relying on them. Sume's docs do not describe a monthly spend cap, only the balance and reservation described in the spend-limit post.
Sources
Related posts
More in Developers
- Face swap API: quality has no default, unlike avatar videos
Avatar videos default to plus when quality is omitted. Sume's Beta face swap has no default: quality is required and takes standard, plus or max.
- FLUX image URL expires after 10 minutes: what Sume returns
Black Forest Labs says generated FLUX image URLs expire after 10 minutes. Sume returns Sume-hosted signed URLs; here is how to fetch and keep the file.
- frame_images plus input_references in one request: which wins?
When a Sume video request carries both frame_images and input_references, frame_images wins and the job runs as image-to-video. What that means for references.
- Gemini CLI MCP timeout default vs Sume's 55-second jobs_wait
Gemini CLI's MCP timeout defaults to 600,000 ms. Sume's jobs_wait holds at most 55 seconds per call: repeat it on wait_slice_expired, never resubmit.
Written by Sume