# Error Handling
ARES uses conventional HTTP status codes and a consistent JSON error format across all endpoints. This page documents the error response structure, status code meanings, and common errors with their solutions.
---
## Error Response Format
All errors return a JSON object with an `error` field containing a human-readable message:
```json
{
"error": "Human-readable error message"
}
```
The HTTP status code indicates the category of error. The `error` string provides specific details about what went wrong.
---
## HTTP Status Codes
### Success Codes
| `200` | OK | Successful read or update operation |
| `201` | Created | Resource successfully created (tenant, agent, API key) |
| `204` | No Content | Successful delete with no response body |
### Client Error Codes
| `400` | Bad Request | Malformed JSON, missing required fields, invalid parameter types |
| `401` | Unauthorized | Missing or invalid authentication credentials |
| `403` | Forbidden | Valid credentials but insufficient permissions for this operation |
| `404` | Not Found | Resource does not exist, or does not belong to your tenant |
| `409` | Conflict | Resource already exists (e.g., duplicate tenant name or agent name) |
| `422` | Unprocessable Entity | Request is well-formed but contains invalid values (e.g., unknown tier, invalid model name) |
| `429` | Too Many Requests | Rate limit or quota exceeded |
### Server Error Codes
| `500` | Internal Server Error | Unexpected server-side failure |
---
## Common Errors and Solutions
### Authentication Errors
**Missing API key:**
```
HTTP 401
{"error": "Missing authorization header"}
```
Add the `Authorization: Bearer ares_xxx` header to your request.
**Invalid API key:**
```
HTTP 401
{"error": "Invalid API key"}
```
Verify that the API key is correct and has not been revoked. API keys start with `ares_`.
**Missing admin secret:**
```
HTTP 401
{"error": "Missing X-Admin-Secret header"}
```
Admin endpoints require the `X-Admin-Secret` header, not the `Authorization` header.
**Invalid admin secret:**
```
HTTP 401
{"error": "Invalid admin secret"}
```
Verify the admin secret matches the value configured in `ares.toml`.
### Resource Errors
**Agent not found:**
```
HTTP 404
{"error": "Agent not found: risk-analyzer"}
```
The agent does not exist for your tenant. Check the agent name with `GET /v1/agents`. Agent names are case-sensitive.
**Tenant not found:**
```
HTTP 404
{"error": "Tenant not found"}
```
The tenant ID does not exist. List tenants with `GET /api/admin/tenants` to find the correct ID.
**Duplicate resource:**
```
HTTP 409
{"error": "Agent with name 'risk-analyzer' already exists for this tenant"}
```
An agent with this name already exists. Use a different name or update the existing agent.
### Validation Errors
**Invalid tier:**
```
HTTP 422
{"error": "Invalid tier: 'gold'. Valid tiers: free, dev, pro, enterprise"}
```
Use one of the supported tier values.
**Missing required field:**
```
HTTP 400
{"error": "Missing required field: name"}
```
Include all required fields in your request body. Refer to the API documentation for the specific endpoint.
**Invalid JSON:**
```
HTTP 400
{"error": "Invalid JSON in request body"}
```
Ensure your request body is valid JSON. Check for trailing commas, unquoted keys, or mismatched brackets. Verify the `Content-Type: application/json` header is set.
### Rate Limit Errors
**Quota exceeded:**
```
HTTP 429
{"error": "Monthly request quota exceeded"}
```
Your tenant has used all allocated requests for the current billing period. Wait until the period resets or contact your administrator to upgrade your tier.
**Daily limit:**
```
HTTP 429
{"error": "Daily request limit reached for your tier"}
```
Your tenant has hit the daily rate cap. Wait until the next UTC day or upgrade your tier.
See [Rate Limits and Quotas](../platform/rate-limits.md) for details on limits by tier.
### Server Errors
**Internal server error:**
```
HTTP 500
{"error": "Internal server error"}
```
An unexpected error occurred on the server. These are not caused by your request. If the error persists, check service health via `GET /api/admin/services` or inspect server logs.
---
## Error Handling Best Practices
1. **Always check the HTTP status code first.** The status code tells you the error category before you parse the response body.
2. **Parse the error message for user display.** The `error` field is written to be human-readable and safe to show to end users.
3. **Retry on 429 and 500.** Rate limit errors (429) should be retried with exponential backoff. Server errors (500) may be transient — retry once or twice before treating as a permanent failure.
4. **Do not retry on 400, 401, 403, 404, 409, or 422.** These indicate problems with the request itself. Fix the request before retrying.
5. **Log the full response.** When debugging, log both the HTTP status code and the response body. The error message often contains the specific field or value that caused the problem.
### Example: Robust Error Handling (Python)
```python
import requests
def run_agent(api_key, agent_name, input_data):
response = requests.post(
f"http://localhost:3000/v1/agents/{agent_name}/run",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
json={"input": input_data},
)
if response.status_code == 200:
return response.json()
error = response.json().get("error", "Unknown error")
if response.status_code == 401:
raise AuthenticationError(f"Authentication failed: {error}")
elif response.status_code == 404:
raise AgentNotFoundError(f"Agent '{agent_name}' not found: {error}")
elif response.status_code == 429:
raise RateLimitError(f"Rate limited: {error}")
elif response.status_code >= 500:
raise ServerError(f"Server error: {error}")
else:
raise APIError(f"API error ({response.status_code}): {error}")
```
### Example: Robust Error Handling (JavaScript)
```javascript
async function runAgent(apiKey, agentName, inputData) {
const response = await fetch(
`http://localhost:3000/v1/agents/${agentName}/run`,
{
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ input: inputData }),
}
);
if (response.ok) {
return await response.json();
}
const { error } = await response.json();
switch (response.status) {
case 401: throw new Error(`Authentication failed: ${error}`);
case 404: throw new Error(`Agent '${agentName}' not found: ${error}`);
case 429: throw new Error(`Rate limited: ${error}`);
default: throw new Error(`API error (${response.status}): ${error}`);
}
}
```