APIError Handling
Error Handling
All Quper API errors return a consistent JSON response structure. The primary field is detail, which contains either a string message or an array of validation error objects depending on the error type.
Error Response Format
Standard Error Response
{
"detail": "Resource not found: user with id 'abc-123' does not exist"
}For FastAPI request body validation errors (HTTP 422), the detail field is an array of objects, each identifying the specific field that failed validation:
422 Validation Error Response
{
"detail": [
{
"loc": ["body", "email"],
"msg": "value is not a valid email address",
"type": "value_error.email"
},
{
"loc": ["body", "role_id"],
"msg": "field required",
"type": "value_error.missing"
}
]
}HTTP Status Code Reference
| Status Code | Name | When It Occurs | Resolution |
|---|---|---|---|
| 400 | Bad Request | Request is malformed or contains invalid parameter values that pass type validation but fail business logic checks | Check the detail message and correct the request |
| 401 | Unauthorized | Missing Authorization header, expired token, or invalid token signature | Re-authenticate via Auth0 and retry with a fresh token |
| 403 | Forbidden | Token is valid but the authenticated user lacks the required permission for this operation (e.g., write access for a viewer role) | Contact your admin to update your role or permissions |
| 404 | Not Found | The requested resource (user, group, role, environment) does not exist within the authenticated tenant | Verify the resource ID and tenant context in your JWT |
| 422 | Unprocessable Entity | Request body failed FastAPI / Pydantic schema validation — missing required fields or incorrect types | Check the array of errors in detail for field-level failures |
| 500 | Internal Server Error | Unexpected server-side error (database connection failure, unhandled exception) | Retry the request; if it persists, check service health or contact support |
Handling Errors in Client Code
TypeScript — Error Handling Example
async function apiRequest<T>(url: string, options?: RequestInit): Promise<T> {
const response = await fetch(url, {
...options,
headers: {
"Authorization": `Bearer ${token}`,
"Content-Type": "application/json",
...options?.headers,
},
});
if (!response.ok) {
const error = await response.json();
const message = Array.isArray(error.detail)
? error.detail.map((e) => `${e.loc.join('.')}: ${e.msg}`).join(', ')
: error.detail ?? 'Unknown error';
throw new Error(`API ${response.status}: ${message}`);
}
return response.json();
}422 vs 400
FastAPI returns 422 Unprocessable Entity for request body schema violations (wrong types, missing required fields). HTTP 400 Bad Request is used for business logic failures that pass schema validation (e.g., referencing a non-existent role_id when creating a user). Always inspect the
detail field structure to distinguish between the two.Retry Behavior
The API does not enforce hard rate limits in the current version. However, Redshift-backed endpoints (FinOps queries, health checks) may return 503 Service Unavailable if the Redshift cluster is paused or unreachable. Implement exponential backoff for 5xx errors. Client errors (4xx) should not be retried without first correcting the request.