headroomlabs-ai/headroom · error · HTTPException
Budget exceeded for {budget_period} period
Error message
Budget exceeded for {budget_period} period What it means
After rate limiting, the Anthropic handler asks the cost tracker whether the period budget still has headroom; when check_budget() returns not-allowed the handler releases the pre-upstream semaphore and returns 429 with a detail string built by cost_tracker.budget_denial_detail() — which names the budget period, spend breakdown, and whether enforcement was blocked because part of the spend was booked from Headroom's own token estimate (when the provider returned no usage data). This is a spend-control refusal, not throttling: retrying immediately will keep failing.
Source
Thrown at headroom/proxy/handlers/anthropic.py:1053
await self.metrics.record_rate_limited(provider=provider_name)
# Unit 4: release the pre-upstream semaphore before we
# bail out of the handler via HTTPException — FastAPI's
# exception handler will NOT run our ``finally``.
await _finalize_pre_upstream()
raise HTTPException(
status_code=429,
detail=f"Rate limited. Retry after {wait_seconds:.1f}s",
headers={"Retry-After": str(int(wait_seconds) + 1)},
)
# Budget check
if self.cost_tracker:
allowed, remaining = self.cost_tracker.check_budget()
if not allowed:
# Unit 4: release the pre-upstream semaphore before we
# bail out of the handler via HTTPException.
await _finalize_pre_upstream()
raise HTTPException(
status_code=429,
detail=self.cost_tracker.budget_denial_detail(),
)
# Memory: Get user ID when memory is enabled (fallback to "default" for simple DevEx).
# Reads `request.headers` directly because the local `headers` dict was
# stripped of `x-headroom-*` above for the upstream-bound copy (PR-A5).
memory_user_id: str | None = None
memory_request_ctx = None
if self.memory_handler:
memory_user_id = request.headers.get(
"x-headroom-user-id",
os.environ.get("USER", os.environ.get("USERNAME", "default")),
)
# Per-project memory routing (GH #462). Build the context
# once here so save / search / inject all resolve against
# the same workspace. Tier order: explicit project-id /
# cwd headers → CLI override → system prompt env block.View on GitHub (pinned to 322425c43b)
Solutions
- Read the full denial detail — if it says enforcement was blocked on estimated cost, fix usage reporting (or relax the basis policy) rather than raising the budget.
- Raise the period budget limit if the spend is legitimate.
- Wait for the period to roll over (daily budgets reset at the period boundary), or split the key/workload across budgets.
Example fix
# before budget_limit_usd = 5.0 # agent burns through it mid-run -> 429 # after budget_limit_usd = 25.0 # sized to actual token volume; or reset at period boundary
Defensive patterns
Strategy: fallback
Validate before calling
# Before long runs, query the cost tracker's remaining budget if exposed: # allowed, remaining = cost_tracker.check_budget() # skip or degrade (smaller model, less context) when remaining < estimated_request_cost
Try / catch
resp = await client.post("/v1/messages", json=body)
if resp.status_code == 429 and "Budget" in resp.json()["detail"]:
notify_operator(f"budget exhausted: {resp.json()['detail']}")
switch_to_budgeted_fallback_model() # or pause the batch until period reset Prevention
- Size period budgets from measured token spend, revisiting after model/price changes.
- Alert on spend > 80% of budget so exhaustion never surprises mid-run.
- Understand the basis policy: strict blocking on estimated cost needs usage reporting to work, not a bigger budget.
When it happens
Trigger: The configured spend limit for the current budget period (e.g. daily/monthly) has been reached or exceeded, and a new /v1/messages request arrives; or the budget-basis policy blocks when a request's cost can only be estimated because the provider returned no usage.
Common situations: Long-running agents exhausting a daily cap mid-run; a budget set too low after a model-price change; estimated-cost booking (missing usage in provider responses) pushing measured spend to the limit under a strict basis policy; forgotten budget config left from a test.
Related errors
- Rate limited. Retry after {wait_seconds:.1f}s
- Rate limited. Retry after {wait_seconds:.1f}s
- failed to download {final_url} after {attempts} attempts: {e
- Error: Proxy dependencies not installed. Run: pip install he
- Shutting down...
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/fcc84ad1b8cec910.
Report an issue: GitHub.