Standard HTTP status codes with consistent JSON error objects. Detect and recover from failures programmatically.
Consistent JSON structure on every error. 4xx = client error, 5xx = server issue.
{
"error": "error_code",
"message": "Human-readable description",
"details": {},
"request_id": "req_abc123"
}| Field | Type | Description |
|---|---|---|
error | string | Machine-readable error code (e.g. bad_request, unauthorized). |
message | string | Human-readable error description. |
details | object | Additional context. Present on validation_error and some other codes. |
request_id | string | Unique request identifier. Include when contacting support. |
Use the code (not the message) for programmatic error handling.
| HTTP Status | Error Code | Description |
|---|---|---|
400 | bad_request | Invalid request body or parameters. |
400 | validation_error | Field validation failed (details includes field-level errors). |
401 | unauthorized | Missing or invalid authentication. |
401 | token_expired | Access token has expired. |
403 | forbidden | Insufficient permissions or scope. |
403 | plan_limit | Feature not available on current plan. |
404 | not_found | Resource does not exist. |
409 | conflict | Resource already exists (e.g., duplicate email). |
413 | payload_too_large | Request body exceeds size limit. |
422 | unprocessable_entity | Request understood but cannot be processed. |
429 | rate_limit_exceeded | Too many requests. |
500 | internal_error | HardDrives error. |
502 | upstream_error | AI provider temporarily unavailable. |
503 | service_unavailable | Service under maintenance. |
When the error code is validation_error, the details object contains a fields map with per-field error messages.
{
"error": "validation_error",
"message": "Validation failed",
"details": {
"fields": {
"email": "Must be a valid email address",
"password": "Must be at least 8 characters"
}
}
}Keys in the fields object match request body parameter names. Multiple fields can fail at once.
Check the HTTP status code before parsing the response body. Transient errors (429, 502, 503): retry with exponential backoff. Client errors (400-422): fix the request before retrying.
async function dyvaFetch(url, options = {}) {
const res = await fetch(url, {
...options,
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
...options.headers,
},
});
if (!res.ok) {
const error = await res.json();
switch (error.error) {
case "token_expired":
// Refresh the token and retry
await refreshToken();
return dyvaFetch(url, options);
case "rate_limit_exceeded":
// Wait and retry with backoff
const retryAfter = res.headers.get("Retry-After") || 5;
await new Promise((r) => setTimeout(r, retryAfter * 1000));
return dyvaFetch(url, options);
case "validation_error":
// Surface field-level errors to the UI
console.error("Validation errors:", error.details.fields);
throw new ValidationError(error.details.fields);
default:
throw new Error(`[${error.error}] ${error.message} (request: ${error.request_id})`);
}
}
return res.json();
}Common errors and fixes.
unauthorizedrate_limit_exceededupstream_errorplan_limitEvery API response includes an X-Request-Id header with a unique identifier. Error response bodies also include it in the request_id field.
Include the request_id when contacting support. It lets the team trace the exact request and diagnose faster.
const res = await fetch("https://api.dyva.ai/v1/dyvas", {
headers: { Authorization: `Bearer ${API_KEY}` },
});
// Always available, even on success
const requestId = res.headers.get("X-Request-Id");
console.log("Request ID:", requestId);
if (!res.ok) {
const error = await res.json();
// Also available in the error body
console.error("Error request ID:", error.request_id);
}