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 CodeNameWhen It OccursResolution
400Bad RequestRequest is malformed or contains invalid parameter values that pass type validation but fail business logic checksCheck the detail message and correct the request
401UnauthorizedMissing Authorization header, expired token, or invalid token signatureRe-authenticate via Auth0 and retry with a fresh token
403ForbiddenToken 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
404Not FoundThe requested resource (user, group, role, environment) does not exist within the authenticated tenantVerify the resource ID and tenant context in your JWT
422Unprocessable EntityRequest body failed FastAPI / Pydantic schema validation — missing required fields or incorrect typesCheck the array of errors in detail for field-level failures
500Internal Server ErrorUnexpected 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.