Skip to content

Errors and refusals

RFC 9457 problem details, validation pointers, refusals and their reasons, masked fields and rate limits.

Every error is an application/problem+json body with type, title, status, detail and instance. The type is a stable URI such as /problems/not-found; match on it, not on title.

Statuses

StatusMeaningWhat to do
400Malformed request, such as an unknown query parameter or a missing Idempotency-KeyFix the request
401Missing, expired or revoked credentialRenew the credential
404The resource does not exist, or you may not see itCheck the identifier and your access
409Conflict, such as an idempotency key reused with another bodyUse a new key for a new action
412If-Match is staleRead again and retry
422Validation failed, or a rule refused the requestRead errors or refusal
428If-Match is missingSend the ETag you read
429Rate limitedWait for Retry-After

Validation errors

A 422 with errors lists one JSON Pointer per invalid member:

{
  "type": "/problems/validation",
  "title": "Unprocessable Content",
  "status": 422,
  "errors": [{ "pointer": "/currency", "detail": "must match ^[A-Z]{3}$" }]
}

Refusals

A 422 with refusal means XOS declined to answer or act, and reason says why:

RefusalMeaning
NO_ANSWERThe data needed to answer does not exist yet. XOS will not guess.
UNRATIFIEDThe value exists but has not been ratified, so it cannot be relied on.
REFUSEA rule forbids the action, such as a disallowed transition or a separation of duties rule. rule names it.

A refusal is an answer, not a fault. Show the reason to the person and never retry it unchanged.

Masked fields

A restricted field you may not read stays in the response as { "masked": true, "reason": "..." }, so the shape of the row never changes with your access.

Rate limits

Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. A 429 carries Retry-After in seconds. The SDKs wait and retry 429, 502, 503 and 504 for you, twice by default, reusing the same Idempotency-Key.

In the SDKs

Each status raises its own error class: XosValidationError, XosRefusalError (with refusal, reason and rule), XosPreconditionFailedError, XosNotFoundError, XosRateLimitError and so on, all subclasses of XosApiError carrying the full problem. Transport failures raise XosNetworkError.