Skip to main content
The Causeloop API uses a consistent error envelope for all failure responses. Every error is JSON with a top-level error object.

Error response shape

{
  "error": {
    "code": "not_found",
    "message": "Issue iss_01abc123 not found",
    "trace_id": "7f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
    "details": {
      "id": "iss_01abc123"
    }
  }
}
error.code
string
required
Machine-readable error code. Use this field for programmatic error handling.
error.message
string
required
Human-readable description of the error. Do not rely on this string in code — it may change. Use code instead.
error.trace_id
string
required
Unique correlation ID for this request. Include this value when contacting support — it links to logs, audit events, and the outbound X-Request-Id response header.
error.details
object
Optional map of field-level error messages. Present on validation errors to pinpoint which input field failed and why.

HTTP status codes

StatusMeaning
400Bad request — malformed body, invalid query parameter, or validation error.
401Unauthorized — missing, invalid, or expired Authorization token.
403Forbidden — authenticated but lacking the required scope or permission.
404Not found — the resource does not exist or is not visible to this token.
409Conflict — the operation conflicts with existing state (e.g. duplicate name).
422Unprocessable entity — the request was well-formed but semantically invalid.
429Too many requests — rate limit exceeded. See Rate Limits.
500Internal server error — unexpected error. Retry with exponential backoff.

Error codes

CodeStatusDescription
validation_error400Request body or query params failed validation. Check details for field-level messages.
unauthorized401Missing or invalid Authorization header, or expired token.
invalid_grant401The subject_token passed to /auth/exchange is invalid or could not be verified.
forbidden403Valid token but insufficient scope for this operation.
mfa_required403MFA enrollment is required by this workspace.
sso_required403SSO is enforced for this workspace — use the SSO flow.
not_found404The requested resource does not exist.
conflict409The operation would create a duplicate (e.g. a service account with the same name).
rate_limited429Too many requests from this IP. See the Retry-After header.
internal_error500Unexpected server error.

Validation errors

When request validation fails (status 400, code validation_error), the details object maps field names to error messages:
{
  "error": {
    "code": "validation_error",
    "message": "Request validation failed",
    "trace_id": "7f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
    "details": {
      "title": "field required",
      "severity": "value is not a valid enumeration member"
    }
  }
}
The field name in details is the dot-path to the invalid field in the request body (e.g. connector.config.api_key).

Handling errors

async function apiCall(url, options = {}) {
  const resp = await fetch(url, {
    ...options,
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });

  if (resp.ok) return resp.json();

  const body = await resp.json().catch(() => ({}));
  const err = body.error ?? {};

  switch (err.code) {
    case 'unauthorized':
      // Token expired — refresh and retry
      await refreshToken();
      return apiCall(url, options);

    case 'validation_error':
      console.error('Validation failed:', err.details);
      throw new Error(`Validation error: ${JSON.stringify(err.details)}`);

    case 'rate_limited':
      // Handled separately in the retry wrapper — see Rate Limits docs
      throw Object.assign(new Error('Rate limited'), { retryAfter: resp.headers.get('Retry-After') });

    case 'not_found':
      throw Object.assign(new Error(`Not found: ${err.message}`), { status: 404 });

    default:
      console.error(`API error [${err.trace_id}]:`, err.message);
      throw new Error(`API error (${err.code}): ${err.message}`);
  }
}

5xx errors and retries

500 Internal Server Error responses indicate an unexpected server-side failure. They are safe to retry with exponential backoff. Always include the trace_id from the error body if you report the issue to support.
Pass the trace_id to Causeloop support when reporting unexpected errors — it ties directly to the server-side logs for that request.