anoman
Docs · Errors

Error code reference.

Every HTTP status and error.code the gateway returns, what causes it, and how your client should handle it.

Error response shape

Standard error body

Every error response from Anoman is a single JSON object with an error key. The shape matches OpenAI’s error envelope so existing SDK error handling works unchanged.

{
  "error": {
    "type": "invalid_request_error" | "guardrail_error" | "rate_limit_error" | "provider_error" | "billing_error",
    "code": "machine_readable_code",
    "message": "Human-readable explanation",
    "param": "messages.0.content"   // (optional) which field caused the error
  }
}

The type field groups errors into five families; code is the specific machine-readable string you should switch on in client code.

Reference

All error codes

Codes are grouped by family. Retryable column tells you whether a retry-with-backoff is the appropriate response.

HTTPCodeTypeCauseRetry?
401auth_missinginvalid_requestNo Authorization headerNo
401auth_invalidinvalid_requestMalformed or unknown keyNo
403auth_revokedinvalid_requestKey was revokedNo
402budget_exceededbillingPer-key monthly USD cap hitNo
402insufficient_creditsbillingPrepaid balance exhaustedNo
402token_quota_exceededbillingWeekly or monthly token cap hit for a model tier classNo
403prompt_injectionguardrailDeBERTa classifier flagged the user contentNo
403pii_blockedguardrailPII detected and policy mode is `block`No
403content_violationguardrailContent moderation blocked the requestNo
403tool_deniedguardrailTool name appears in policy denylistNo
403tool_not_allowedguardrailTool not in policy allowlistNo
400model_not_foundinvalid_requestModel slug not in our catalogNo
400context_length_exceededinvalid_requestPrompt + completion exceeds model context windowNo
400vision_not_supportedinvalid_requestImage input passed to a text-only modelNo
429rate_limit_exceededrate_limitRPM or TPM burst guard trippedYes
429concurrent_limit_exceededrate_limitInflight cap reached for this keyYes
503provider_unavailableproviderAll upstream routes failed after retriesYes
504provider_timeoutproviderUpstream did not respond within 120sYes
503cost_cap_openproviderCircuit breaker open on the upstreamYes

Auth + budget + guardrail errors return immediately and won’t succeed on retry — fix the request or the configuration. Rate limit + provider errors are transient — retry with exponential backoff and respect the Retry-After header.

Guardrail blocks

Reading 403 guardrail errors

When a guardrail blocks a request the response is 403 and the type is guardrail_error. The full guardrail pass/fail breakdown is also exposed on the successful response in the _anoman.guardrails object, see Guardrails.

{
  "error": {
    "type": "guardrail_error",
    "code": "prompt_injection",
    "message": "Request blocked by prompt injection detector (score 0.94 > threshold 0.85)."
  }
}

Guardrail block is the right behavior — don’t silently retry. Either surface to the end user (with a generic refusal message) or escalate to a human review queue if the surface is high-stakes.

Spend & rate boundaries

Reading 402 and 429 responses

Don’t confuse the spend boundary with the flood guard. 402 token_quota_exceeded means you hit a model tier class’s weekly or monthly token cap — not retryable until the window rolls over (buy a token pack, upgrade, or switch model class). 429 rate_limit_exceeded means an RPM/TPM burst guard filled up, and concurrent_limit_exceeded means too many simultaneous inflight requests — both transient, safe to retry with backoff.

// HTTP 402 Payment Required — the spend boundary on flat tiers.

{
  "error": {
    "type": "billing_error",
    "code": "token_quota_exceeded",
    "message": "Monthly token cap reached for the 'premium' model tier class.",
    "model_tier_class": "premium",
    "window": "monthly"
  }
}

Full per-tier limits + headers reference at Rate limits.

Retry recipe

Exponential backoff with jitter

The OpenAI / Anthropic SDKs already retry by default, but the defaults are conservative. Here’s an explicit pattern that respects Retry-After:

import time
import random
from openai import OpenAI
from openai import APIStatusError

client = OpenAI(base_url="https://api.anoman.io/v1", api_key="anm-sk-...")

def chat_with_retry(messages, model="gpt-4o-mini", max_attempts=5):
    for attempt in range(max_attempts):
        try:
            return client.chat.completions.create(model=model, messages=messages)
        except APIStatusError as e:
            # Retry on 429 (rate limit), 503 (provider unavailable),
            # 504 (gateway timeout). Bail on 4xx auth/budget errors.
            if e.status_code not in {429, 503, 504}:
                raise
            if attempt == max_attempts - 1:
                raise
            # Respect Retry-After header when present.
            retry_after = float(e.response.headers.get("retry-after", 0))
            sleep = retry_after or min(2 ** attempt + random.random(), 30)
            time.sleep(sleep)

See guardrails fire on real requests.

The dashboard surfaces every block with the prompt that caused it.