Error codes
Why Prune blocked a call, and what to change.
Quick answer
When Prune blocks a call it returns the reason in the X-Prune-Shield-Code header and links to the matching entry below in X-Prune-Docs-Url and the docs_url field of the JSON body. A blocked call never reaches the provider, so it costs nothing. Errors from the provider itself (a bad model name, an invalid key) are passed through unchanged and have no Shield code.
What a blocked response looks like
A 429 with these headers: X-Prune-Shield-Code: spend_cap, X-Prune-Shield-Action: reject and X-Prune-Docs-Url: https://www.withprune.com/docs/errors#spend_cap. The body:
{
"code": "spend_cap",
"error": "Daily spend cap of $200.00 reached (current: $200.13).",
"message": "Daily spend cap of $200.00 reached (current: $200.13).",
"cap_usd": 200.0,
"spent_usd": 200.13,
"docs_url": "https://www.withprune.com/docs/errors#spend_cap"
}from openai import OpenAI, APIStatusError
try:
resp = client.chat.completions.create(model="gpt-4o", messages=messages)
except APIStatusError as e:
code = e.response.headers.get("X-Prune-Shield-Code")
if code == "customer_budget":
show_upgrade_prompt()
elif e.status_code == 503 and code:
retry_later()
else:
print(code, e.response.headers.get("X-Prune-Docs-Url"))
raiseSpend limits
Shield stopped the call before it reached the provider, so it cost nothing.
spend_cap HTTP 429
This API key reached its daily spend cap in Shield. The count resets at 00:00 UTC. Cache hits do not count.
Fix: Open Shield in the dashboard and raise the cap or switch mode. Check Activity first to see what spent it.
anomaly_spike HTTP 429
Spend on this key jumped far above its normal rate (Balanced mode blocks at 8x).
Fix: If the spike is expected (a launch, a batch job), raise the multiplier or turn spike detection off for that key in Shield.
token_budget HTTP 429
This key used up the daily token budget set for this model.
Fix: Raise the per-model token budget in Shield, or send the work to a cheaper model.
customer_budget HTTP 429
The customer in X-Prune-Customer-Id crossed their monthly budget. The response includes spend, budget and period. Budgets reset on the 1st (UTC).
Fix: Raise the budget on the Customers page, or show your user an upgrade prompt. This is the code to catch for per-user limits.
rate_limit HTTP 429
Too many requests per minute on this key (Balanced allows 300, Locked down 60).
Fix: Back off and retry, or raise the rate limit in Shield.
plan_limit HTTP 402
Your Prune plan's monthly request quota is used up.
Fix: Upgrade on the Billing page. Quotas reset monthly.
free_trial_ended HTTP 402
The free trial on this account has ended.
Fix: Pick a plan on the Billing page.
Agent guards
Limits on a single agent run. Send X-Prune-Run-Id on every call of the run so they apply.
run_budget HTTP 429
This run has spent the amount in X-Prune-Run-Budget-Usd.
Fix: Look at the run in Activity. If it was a real task, raise the budget. If it was looping, fix the tool it kept calling.
run_budget_missing_run_id HTTP 400
X-Prune-Run-Budget-Usd was sent without X-Prune-Run-Id, so there is no run to count against.
Fix: Send one X-Prune-Run-Id per agent run on every call of that run.
agent_step_budget HTTP 429
The run made more calls than X-Prune-Max-Steps (default 50 for tool-using calls).
Fix: Raise X-Prune-Max-Steps if the task really needs more steps (up to 500). Otherwise the agent is stuck.
agent_loop HTTP 429
The same step repeated three times in one run.
Fix: Fix the tool or prompt the agent is retrying. Raising limits will not help here.
loop_detected HTTP 429
Too many near-identical requests in a short window (default 100 in 60 seconds), even without a run ID.
Fix: Find the retry loop in your code. Raise the threshold in Shield only if the traffic is intended.
Access rules
Allowlists and blocks you set in Shield.
ip_blocked HTTP 403
The request came from an IP that is not on this key's allowlist.
Fix: Add the server's IP in Shield, or remove the allowlist.
provider_blocked HTTP 403
This key is not allowed to call this provider.
Fix: Add the provider to the key's allowed providers in Shield.
model_blocked HTTP 403
This key is not allowed to call this model.
Fix: Add the model to the key's allowed models in Shield, or call an allowed one.
tool_policy HTTP 403
The request asked the model to call a tool your policy denies.
Fix: Check the tool allow and deny lists in Shield. Keep dangerous tools behind a human approval.
Content checks
Checks on what goes into and comes out of the model.
prompt_injection HTTP 403
The input looked like a prompt injection and you opted into blocking with X-Prune-Injection: block.
Fix: Review the input in Activity. Use detect mode (the default) if you only want a signal.
prompt_injection_signal HTTP 200
Not a block. The input looked like a prompt injection and the call went through (detect mode).
Fix: Log it on your side, or switch to block mode for this route.
canary_leak HTTP 403
The canary token Prune added to your system prompt appeared in the output, so the model was leaking its instructions.
Fix: Treat the input as an attack. Turn off X-Prune-Shield-Canary-Block if you only want to log leaks.
Voice
Limits on voice calls and text to speech.
call_budget HTTP 429
The call spent the amount in X-Prune-Call-Budget-Usd.
Fix: Raise the call budget or end long calls sooner.
call_duration HTTP 429
The call ran longer than X-Prune-Call-Max-Seconds.
Fix: Raise the limit if long calls are expected.
repeat_loop HTTP 429
The voice agent said the same line too many times.
Fix: Fix the step the agent keeps repeating.
card_readback_blocked HTTP 422
Text to speech refused to read a card number aloud.
Fix: Mask the number, or send X-Prune-Allow-Card-Readback: true if you really need it.
Prune could not check
Prune fails closed: if it cannot check a limit, it rejects the call instead of letting it through unguarded. These are safe to retry.