# Handle errors: what each status means and what to do

A failed request tells you two things: a status code, and a body that names what went wrong. Read the status first, then the body, and decide whether to fix the request, fix the credentials or read the record back.

## 1. Read the error body

A failure returns an envelope. The outer message summarises it. The `errors` array names each parameter that failed, with a `userMessageGlobalisationCode` that stays stable, so key your handling off the code and not off the message text.

- `httpStatusCode`: The status, repeated in the body.
- `defaultUserMessage`: A summary you can show a person.
- `userMessageGlobalisationCode`: A stable code for the failure as a whole.
- `errors[].parameterName`: The field that failed.
- `errors[].userMessageGlobalisationCode`: A stable code for that field's failure.

## 2. Act on the status code

Each status has one sensible response.

| Status | What it means | What to do |
| --- | --- | --- |
| `400` | Validation failed, or a domain rule refused the request. | Fix the fields the `errors` array names. Do not send the same request again. |
| `401` | The credentials were not accepted. | Check the username and the password. |
| `403` | The user lacks a permission. The body names it. | Grant the permission to a role the user holds, or use another user. |
| `404` | The id does not exist on this tenant. | Check the id, and check that the tenant header names the right tenant. |
| `409` | The request conflicts with the current state of the record. | Read the record, then decide. Do not send the same request again. |
| `422` | A partner endpoint refused the request under a named rule. | Find the `sourcing/` code the response names and follow the table below. |

## 3. Decide whether to retry

A request that failed validation fails again until you change it, so a retry only helps after a fix.

Some endpoints list an Idempotency-Key header. Send one on each of them, and send the same key when you repeat the same request. Creating a partner and revising terms return 409 when a key is reused with a different body.

For any other write, a timeout does not tell you whether the write was applied. Read the record back first, and send the request again only if the change is not there.

## 4. Partner error codes

The partner endpoints return a code that names the rule. These are the ones the reference documents.

| Code | Status | What to do |
| --- | --- | --- |
| `sourcing/partner_has_no_active_terms` | 422 | Add terms to the partner, then activate it. |
| `sourcing/external_id_taken` | 409 | Choose an external id no other partner uses. |
| `sourcing/terms_overlap` | 409 | Set `effective_from` after the start of the version being superseded. |
| `sourcing/terms_line_required` | 422 | Send at least one fee line. |
| `sourcing/fee_shape_invalid` | 422 | Make the fee fields match the fee method. |
| `sourcing/slab_coverage_invalid` | 422 | Make the bands start at zero, join up, and leave exactly one open at the top. |
| `sourcing/bank_account_duplicate` | 409 | The partner already has this account. Use the existing one. |
| `sourcing/last_contact_cannot_be_deleted` | 422 | Add another contact before you remove this one. |
| `sourcing/use_primary_endpoint` | 422 | The contact is already primary. No change is needed. |
| `sourcing/document_not_removable` | 409 | Upload the correct file as a new document. A verified or rejected document stays. |
| `sourcing/state_change_already_pending` | 409 | Decide or withdraw the open request first. |
| `sourcing/checker_is_maker` | 422 | Have a different user approve. |
| `sourcing/loan_already_attributed` | 409 | Correct the existing attribution instead of adding one. |
| `sourcing/correction_reason_required` | 422 | Send a `reason`. |
| `sourcing/draft_already_decided` | 409 | Read the draft. It was already approved or rejected. |
| `sourcing/payment_exceeds_invoice_total` | 422 | Record an amount no greater than what is outstanding. |
| `sourcing/payment_already_reversed` | 409 | The payment was reversed once. Record a fresh payment to settle again. |
| `sourcing/payment_not_reversible` | 409 | A reversal cannot be reversed. Record a fresh payment. |
| `sourcing/invoice_already_paid` | 409 | Reverse the payments, then cancel the invoice. |
| `sourcing/invoice_cancel_reason_required` | 422 | Send a `reason`. |

## Where to go next

- [Conventions: dates, commands and pagination](https://developer.lokta.ai/conventions)
- [Quickstart](https://developer.lokta.ai/guides/quickstart/)
