Error Handling
Understand and handle ZenSearch API errors.
Error Response Format
All errors follow a consistent format:
{
"error": {
"code": "error_code",
"message": "Human-readable error message",
"details": {
"field": "Additional context"
}
},
"meta": {
"requestId": "req_abc123"
}
}
HTTP Status Codes
| Code | Description |
|---|---|
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Authentication required |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource doesn't exist |
| 409 | Conflict - Resource already exists |
| 422 | Unprocessable - Validation failed |
| 429 | Too Many Requests - Rate limited |
| 500 | Internal Error - Server error |
| 503 | Service Unavailable - Temporarily down |
Error Codes
Authentication Errors
| Code | Description |
|---|---|
unauthorized | Missing or invalid API key |
token_expired | API key has expired |
invalid_token | Malformed token |
Permission Errors
| Code | Description |
|---|---|
forbidden | Lacking required permissions |
team_access_denied | No access to team |
resource_access_denied | No access to resource |
Validation Errors
| Code | Description |
|---|---|
invalid_request | Request body is malformed |
missing_parameter | Required parameter missing |
invalid_parameter | Parameter value is invalid |
validation_failed | Multiple validation errors |
Resource Errors
| Code | Description |
|---|---|
not_found | Resource doesn't exist |
already_exists | Resource already exists |
resource_deleted | Resource was deleted |
Rate Limit Errors
| Code | Description |
|---|---|
rate_limit_exceeded | Too many requests |
quota_exceeded | Plan quota exceeded |
Server Errors
| Code | Description |
|---|---|
internal_error | Unexpected server error |
service_unavailable | Service temporarily down |
timeout | Request timed out |
Handling Errors
JavaScript/TypeScript
import { ZenSearchError } from '@zensearch/sdk';
try {
const result = await client.search({ query: 'test' });
} catch (error) {
if (error instanceof ZenSearchError) {
switch (error.code) {
case 'rate_limit_exceeded':
await sleep(error.retryAfter * 1000);
// Retry
break;
case 'unauthorized':
// Refresh API key
break;
default:
console.error('API error:', error.message);
}
}
}
Python
from zensearch import ZenSearchError
try:
result = client.search(query="test")
except ZenSearchError as e:
if e.code == "rate_limit_exceeded":
time.sleep(e.retry_after)
# Retry
elif e.code == "unauthorized":
# Handle auth error
pass
else:
print(f"API error: {e.message}")
Validation Error Details
Validation errors include field-specific details:
{
"error": {
"code": "validation_failed",
"message": "Request validation failed",
"details": {
"errors": [
{
"field": "query",
"message": "Query is required"
},
{
"field": "limit",
"message": "Limit must be between 1 and 100"
}
]
}
}
}
Retry Strategy
Retryable Errors
| Code | Retry |
|---|---|
| 429 | Yes, after Retry-After |
| 500 | Yes, with backoff |
| 503 | Yes, with backoff |
| 400 | No |
| 401 | No |
| 403 | No |
| 404 | No |
Backoff Example
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3
): Promise<T> {
let lastError: Error;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (!isRetryable(error)) {
throw error;
}
const delay = Math.min(1000 * Math.pow(2, attempt), 30000);
await sleep(delay);
}
}
throw lastError;
}
Debugging
Request ID
Every response includes a request ID:
X-Request-ID: req_abc123
Include this in support requests for faster debugging.
Logging
Log errors with context:
logger.error('API request failed', {
requestId: error.requestId,
code: error.code,
message: error.message,
endpoint: '/v1/search',
params: { query: 'test' }
});
Next Steps
- Rate Limits - Understand limits
- API Overview - Full API reference