Errors & status codes
The gateway uses standard HTTP status codes alongside a JSON error body with a machine-readable code field. Always branch on code, not on the human-readable message (which may change).
{ "error": { "code": "policy_block", "message": "Request blocked by policy rule." }}Error catalog
Section titled “Error catalog”| Code | HTTP | Retry? | Meaning |
|---|---|---|---|
invalid_api_key |
401 | No | API key not found, revoked, or malformed. Check the key and the Authorization / X-API-Key header. |
policy_block |
403 | No | The Policy Engine’s terminal action was BLOCK. The X-Matched-Rule response header names the rule. |
model_not_found |
404 | No | The requested provider/model-id is not recognized or not available to your org. |
context_length_exceeded |
400 | No | The request exceeds the model’s context window. Shorten the input. |
invalid_request |
400 | No | Malformed request body (bad JSON, missing required field, wrong type). |
quota_exceeded |
429 | Backoff | Rate limit or token budget exceeded. See Rate limits. |
provider_unavailable |
503 | Backoff | Every provider in the routing chain was unavailable. |
On a policy_block, the error body carries two extra fields beyond code and message: type ("policy_error") and rule_id (the rule that produced the block, matching the X-Matched-Rule header). The rule_id also matches matched_rule_id in the audit log, so you can cross-reference an unexpected block. See Policy decisions for the full body.
Retry guidance
Section titled “Retry guidance”- Do not retry
4xxerrors except429— they are deterministic and will fail identically. Fix the request instead. - Retry with exponential backoff on
429(quota_exceeded) and503(provider_unavailable). Start at ~1s, double each attempt, cap at ~30s, and add jitter. HonorX-RateLimit-Reseton429(see Rate limits). policy_blockis intentional. A403 policy_blockmeans your organization’s policy blocked the content — surface it to the user; do not retry.
DLP outcomes vs errors
Section titled “DLP outcomes vs errors”DLP redaction is not an error. When DLP redacts content inline, the request still succeeds (200) with the content modified. In streaming responses you may also receive dlp_correction events (content was corrected mid-stream) and output_blocked events (the response was stopped by DLP). See DLP results.
Not every enforcement action is an error
Section titled “Not every enforcement action is an error”BLOCK is the only terminal policy action that returns a non-2xx status (403 policy_block). The other actions surface on a successful response — read the X-Policy-Action header to tell them apart:
REDACTandROUTE_TOreturn200; the content was sanitized or the request was rerouted, and your call succeeded normally.CANCELreturns200with a truncated stream — the output was halted mid-response. Treat the partial content as incomplete; the request cannot be retried because the provider round-trip already happened.
See Policy decisions for the full semantics of each action.
Next steps
Section titled “Next steps”- Rate limits — headers and backoff for
429 quota_exceeded. - Policy decisions — how
BLOCK,REDACT,ROUTE_TO, andCANCELare decided and surfaced. - Chat completions — streaming
dlp_correctionandoutput_blockedevents.