CodamAIDocs
Topicdone

The error format

Which fields an error response has, and what a client should branch on.

Variants
Error response from CDMSValidation error with violationsRefusal by the filter chainResponse without a bodyStatus 200 in error shape (LENIENT)

What this is about

When a request goes wrong, CDMS answers with an error status (400 and above) and an error response. The error response is a small JSON object without data. It tells you what happened, in a form a program can evaluate.

An error response, labeled

The read role is missing
Request
POST /api/rest/hr/employee/read/5a2b…
{ "response": ["name"] }
Response 403, labeled
{
  "error":      "MissingPermissionException",   ← kind of error
  "messageKey": "missing-permission|hr-employee-read",
                 └── key ──────┘ └── detail ──┘  ← branch on this
  "code":       "403",                          ← status as text
  "layer":      "validation"                    ← layer, for debugging only
}
Fieldalways present?Meaningin the client
erroryesname of the error class, e.g. ApiValidationExceptionwrite it to the log
messageKeyyesfixed key, often with details after |branch on this
messageonly in the server’s debug modetechnical text of the causenever show it, never evaluate it
codeyesthe HTTP status as text, e.g. "422"same as the status of the response
layeryeslayer in which the error occurredfor debugging only
violationsonly for validation errorsall violated field rules with pathmap them to the form fields
idonly in the LENIENT special caseid of the created objectkeep it, read later
stacktraceonly in the server’s debug modetechnical call stacknever evaluate it

The messageKey in detail

The messageKey has the form key|detail|detail. Before the first | is the key, i.e. the kind of problem. After it, depending on the error, come details such as a field name, a role name, an id or a value.

messageKeykeydetails
missing-permission|hr-employee-readmissing-permissionthe missing role
invalid-value|data.amountinvalid-valuepath of the field in the body
wrong-value-in-where|amount|abcwrong-value-in-wherefield and value of the filter
recursive-create-not-allowed|employeesrecursive-create-not-allowedthe relation
not-foundnot-foundnone
validation-failedvalidation-failednone, the details are in violations
CDMS_OPTIMISTIC_LOCK_CONFLICTCDMS_OPTIMISTIC_LOCK_CONFLICTnone

This is how you get the key in the client:

Separating key and details
TypeScript
const [key, ...details] = body.messageKey.split('|');
// key     = "missing-permission"
// details = ["hr-employee-read"]
Branching
switch (key) {
  case 'missing-permission': …  // role missing
  case 'not-found':          …  // object gone or invisible
  case 'validation-failed':  …  // violations into the form
  default:                   …  // general message
}

Keys from the persistence layer are written in capitals (CDMS_TENANT_REQUIRED), the others in lowercase with hyphens (missing-id). For the client this does not matter: compare the key character by character, exactly as it is.

Three shapes of error bodies

Not every refusal comes from CDMS itself. The CIAS filter chain runs first and answers in its own shape, and some refusals have no body at all.

Who answered?
CDMS
body with messageKey
  • error, messageKey, code, layer
  • every refusal from the role check on
  • also 400 for a request that cannot be read
Filter chain, tenant
403 with error, without messageKey
  • {"error": "cias.authentication.tenant-unresolved", "message": "request refused"}
  • the tenant cannot be determined, is not served or is missing
  • here the key is in the field error
without a body
no CDMS JSON
  • 401: token invalid or expired, header WWW-Authenticate
  • 403: no token at all
  • 404: the path does not exist

More about the refusals of the filter chain in Access without a token and 401, 403 or 404?.

Validation: violations

Only a validation error has a list violations. Each entry names the field with its path and the violated rule:

Two required fields are missing
Request
POST /api/rest/crm/customer/create
{ "data": { "name": "" }, "response": ["id"] }
Response 422
{
  "error": "ApiValidationException",
  "messageKey": "validation-failed",
  "code": "422",
  "layer": "API",
  "violations": [
    { "field": "name",  "rule": "cannot-be-empty" },
    { "field": "email", "rule": "cannot-be-null" }
  ]
}

How to map the entries to the form fields is described in Getting validation errors into the form. Which rules exist: Validation.

The special case: 200 in error shape

After a create in LENIENT mode, creating can succeed while only the read-back fails. Then you get status 200, but a body in error shape with the id of the new object:

Created, but not read back
Response 200
{
  "error": "CreateSucceededReadFailedException",
  "messageKey": "CDMS_CREATE_SUCCEEDED_READ_FAILED",
  "code": "200",
  "layer": "system",
  "id": "5a2b…"
}
What the client should do
The object exists.
Keep the id and read it later,
do NOT create it again.

See Create and read back: STRICT or LENIENT.

How a client evaluates it

Evaluating a response
  1. 1
    Client
    Status 2xx?
  2. 2
    Client
    yes, and messageKey is CDMS_CREATE_SUCCEEDED_READ_FAILED → created, keep the id
  3. 3
    Client
    yes, otherwise → use data
  4. 4
    Client
    no → read the body if there is one. Does it have a messageKey?
  5. 5
    Client
    yes → evaluate the key before the first |, for 422 also violations
  6. 6
    Client
    no → decide by status: 401 renew the token, 403 with error check the tenant, otherwise a general message

Pitfalls

Where to go next

Sources in the code and the knowledge base
  • CDMS/cdms-rest-api – CdmsExceptionMapper (handleCmsException, handleDefault), ClientErrorTranslator
  • commons – AbstractCodamaiException (httpStatusCode, messageKey, layer, embedded, violations), FieldViolation, GlobalProperties
  • CDMS/cdms-commons – exceptions (ApiValidationException, CreateSucceededReadFailedException and others)
  • commons-persistence – CodamaiPersistenceException, PersistenceErrorCode
  • CIAS/cias-authentication – JwtSessionFilter.refuse, SessionConfig (Http403ForbiddenEntryPoint, oauth2ResourceServer), RequestAdmission
  • documentation/05-api-guide/10-fehler.md, 20-api/06-fehler-und-statuscodes.md
Search