Error Handling for AI Agents
Consistent, machine-parseable error format designed for programmatic consumption by AI agents and automated systems.
Error Envelope
All API errors return a JSON object with a single error key. This shape is stable and safe for programmatic parsing.
json
{
"error": {
"message": "Human-readable error description",
"type": "error_category",
"code": 400,
"param": "field_name"
}
}Error Fields
| Name | Type | Required | Description |
|---|---|---|---|
error.message | string | Required | Human-readable description. Always present. Safe to display to users. |
error.type | string | Required | Error category for programmatic branching. One of: invalid_request_error, authentication_error, rate_limit_error, api_error, insufficient_credits. |
error.code | integer | string | Required | HTTP status code (integer) for standard errors. Semantic string (e.g. 'insufficient_credits') for extended errors. |
error.param | string | null | The request parameter that caused the error. Null when not applicable. |
Error Types Reference
| Name | Type | Required | Description |
|---|---|---|---|
invalid_request_error | 400 | Malformed request, missing required fields, or invalid parameter values. Check error.param for the offending field. | |
authentication_error | 401 | Missing, invalid, or expired API key. Verify the Authorization header. | |
insufficient_credits | 402 | Account balance too low. Extended payload includes error.balance with current/threshold values. | |
rate_limit_error | 429 | Request quota exceeded. Read the Retry-After header for backoff seconds. | |
api_error | 500/502/503 | Gateway or upstream provider failure. Safe to retry with exponential backoff. |
Agent Retry Strategy
Recommended decision tree for AI agents handling errors:
retry-strategy.py
import time
import openai
def call_with_retry(client, max_retries=3, **kwargs):
for attempt in range(max_retries):
try:
return client.chat.completions.create(**kwargs)
except openai.RateLimitError as e:
# 429: wait for Retry-After header value
wait = int(e.response.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
except openai.APIStatusError as e:
error_type = e.body.get("error", {}).get("type", "")
if error_type == "insufficient_credits":
raise # Cannot retry — top up credits
if error_type == "authentication_error":
raise # Cannot retry — fix API key
if error_type == "invalid_request_error":
raise # Cannot retry — fix request payload
if e.status_code >= 500:
# Server error: retry with backoff
time.sleep(2 ** attempt)
else:
raise
raise RuntimeError("Max retries exceeded")Insufficient Credits (402) Extended Shape
The 402 error includes additional fields for balance awareness:
json
{
"error": {
"type": "insufficient_credits",
"message": "Insufficient credit balance",
"code": "insufficient_credits",
"balance": {
"current": 2.5,
"threshold": 5,
"currency": "credits"
},
"actions": {
"top_up_url": "/v1/customer/credits/packages",
"support_url": "/support"
}
}
}Diagnostic Headers
| Name | Type | Required | Description |
|---|---|---|---|
x-request-id | string (UUID) | Always present. Use this for debugging and when contacting support. | |
Retry-After | integer | Present on 429 responses. Number of seconds to wait before retrying. | |
X-RateLimit-Remaining | integer | Remaining requests in the current rate limit window. | |
X-RateLimit-Reset | integer | Unix epoch timestamp when the rate limit window resets. |
Parsing Tip
Always check for the presence of
error key first. A successful response never contains an error field. This makes error detection a single boolean check: if ("error" in response).