> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Error handling

> Learn how to interpret, classify, and resolve error responses returned by Lerian APIs, including HTTP status codes and structured error payload fields.

When integrating with Lerian APIs, robust error handling is essential for a seamless user experience and resilient application performance. This guide explains how errors are structured, how to classify them, and how to respond to different error categories.

## Error response model

***

All Lerian APIs return a structured error object for every error. The format is consistent across all services:

```json theme={null}
{
   "code": "<error_code>",
   "title": "<error_title>",
   "message": "<error_message>"
}
```

**Field definitions:**

* `code`: A unique, stable identifier for the error. Use this field for programmatic error handling.
* `title`: A brief summary of the issue.
* `message`: Detailed, human-readable guidance for resolving the error.

<Tip>
  Always use the `code` field to identify errors programmatically. Titles and messages may evolve to improve clarity, but error codes remain stable.
</Tip>

### Field-level error details

When an error relates to specific fields in the request payload, the response includes a `fields` object with granular details:

<CodeGroup>
  ```json Missing required fields theme={null}
  {
     "code": "CRM-0003",
     "title": "Missing Fields in Request",
     "message": "Your request is missing one or more required fields. Please refer to the documentation to ensure all necessary fields are included in your request.",
     "fields": {
        "document": "document is a required field"
     }
  }
  ```

  ```json Invalid field values theme={null}
  {
     "code": "CRM-0047",
     "title": "Bad Request",
     "message": "The server could not understand the request due to malformed syntax. Please check the listed fields and try again.",
     "fields": {
        "legalName": "legalName is a required field.",
        "parentOrganizationId": "parentOrganizationId must be a valid UUID"
     }
  }
  ```

  ```json Unexpected fields theme={null}
  {
     "code": "CRM-0053",
     "title": "Unexpected Fields in the Request",
     "message": "The request body contains more fields than expected. Please send only the allowed fields as per the documentation. The unexpected fields are listed in the fields object.",
     "fields": {
        "extraField": "extraField is not allowed"
     }
  }
  ```
</CodeGroup>

## Error code structure

***

Every error code follows a standardized format that identifies both the service and the specific error:

```
<PREFIX>-<NNNN>
```

* **PREFIX** (3 letters): Identifies the service or plugin that produced the error.
* **NNNN** (4 digits): A unique number within that service.

### Service prefixes

| Prefix  | Service                         |
| ------- | ------------------------------- |
| **AUT** | Access Manager (authentication) |
| **IDE** | Access Manager (identity)       |
| **CRM** | CRM                             |
| **FEE** | Fees Engine                     |
| **Pix** | Pix                             |
| **BTF** | Bank Transfer (TED)             |
| **TPL** | Reporter                        |
| **TRC** | Tracer                          |

<Note>
  Midaz core uses numeric-only codes (e.g., `0002`, `0009`) without a prefix. All other services include their 3-letter prefix.
</Note>

### Number ranges

Error codes are organized into ranges that indicate the error's origin:

| Range         | Category              | Description                                                     |
| ------------- | --------------------- | --------------------------------------------------------------- |
| `0001`–`0099` | System and middleware | Authentication, authorization, headers, rate limiting           |
| `0100`–`0999` | Service-specific      | Validation, business logic, and domain errors within the plugin |
| `1000`–`1999` | External integration  | Errors originating from external providers or upstream services |

This structure allows you to quickly identify whether an error comes from your request (low numbers), the service's business logic (mid-range), or an external dependency (1000+).

## Error classification

***

Understanding the type of error helps you decide how to respond. Lerian errors fall into three categories:

### Validation errors

Errors caused by incorrect or missing input in the request.

**Characteristics:**

* HTTP status `400` (Bad Request)
* Include a `fields` object when specific fields are at fault
* Always preventable by validating input before sending

**Examples:** Missing required fields, invalid UUIDs, unsupported enum values, fields exceeding maximum length.

**What to do:** Check the `fields` object for specifics. Correct the input and retry.

### Business logic errors

Errors caused by operations that violate domain rules or resource state constraints.

**Characteristics:**

* HTTP status `404` (Not Found), `409` (Conflict), or `422` (Unprocessable Entity)
* Indicate that the request is syntactically valid but cannot be processed

**Examples:** Resource not found, duplicate name conflicts, invalid status transitions (e.g., activating an already active rule), insufficient balance.

**What to do:** Verify the resource exists and is in the expected state. Check the error message for the specific constraint that was violated.

### System errors

Errors caused by infrastructure issues, timeouts, or unexpected failures.

**Characteristics:**

* HTTP status `500` (Internal Server Error), `502` (Bad Gateway), `503` (Service Unavailable), or `504` (Gateway Timeout)
* Not caused by your input — the same request may succeed later

**Examples:** Internal server error, service temporarily unavailable, gateway timeout.

**What to do:** Retry with exponential backoff (see guidance below). If the error persists, contact support.

## HTTP status codes

***

Lerian APIs use a focused set of HTTP status codes:

| Code  | Meaning               | Category                                                |
| ----- | --------------------- | ------------------------------------------------------- |
| `400` | Bad Request           | Validation error — fix the request                      |
| `401` | Unauthorized          | Missing or invalid authentication credentials           |
| `403` | Forbidden             | Valid credentials but insufficient permissions          |
| `404` | Not Found             | The requested resource does not exist                   |
| `409` | Conflict              | The operation conflicts with the current resource state |
| `422` | Unprocessable Entity  | Valid syntax but violates business rules                |
| `429` | Too Many Requests     | Rate limit exceeded — wait and retry                    |
| `500` | Internal Server Error | Unexpected server failure — retry later                 |
| `502` | Bad Gateway           | Upstream service returned an invalid response           |
| `503` | Service Unavailable   | Service temporarily unavailable — retry later           |
| `504` | Gateway Timeout       | Request timed out — retry later                         |

## Retry guidance

***

Not all errors should be retried. The following table helps you decide:

| Error type                | Retryable | Recommended action                                          |
| ------------------------- | --------- | ----------------------------------------------------------- |
| `400` validation errors   | No        | Fix the request payload                                     |
| `401` / `403` auth errors | No        | Check credentials and permissions                           |
| `404` not found           | No        | Verify the resource ID                                      |
| `409` conflicts           | Sometimes | Check current state, then retry if the conflict is resolved |
| `422` business logic      | No        | Adjust the operation to comply with business rules          |
| `429` rate limit          | Yes       | Wait for the retry window, then retry                       |
| `500` internal errors     | Yes       | Retry with exponential backoff                              |
| `502` / `503` / `504`     | Yes       | Retry with exponential backoff                              |

### Exponential backoff strategy

For retryable errors, use exponential backoff to avoid overwhelming the service:

1. **First retry**: Wait 1 second
2. **Second retry**: Wait 2 seconds
3. **Third retry**: Wait 4 seconds
4. **Maximum retries**: Stop after 3–5 attempts
5. **Jitter**: Add a small random delay (0–500ms) to each wait to prevent thundering herd

<Warning>
  Never retry `400`, `401`, `403`, or `422` errors automatically. These indicate issues with your request that must be fixed before retrying.
</Warning>

## Troubleshooting by category

***

### Missing or invalid fields (400)

Most `400` errors include a `fields` object that tells you exactly which fields need attention.

**Common causes:**

* Required field omitted from the request body
* Field value does not match the expected type (e.g., string instead of UUID)
* Field value exceeds maximum length
* Unexpected extra fields in the request body

**Resolution steps:**

1. Read the `fields` object in the error response
2. Compare your request against the API reference for that endpoint
3. Verify field names use `lowerCamelCase` (not `snake_case`)
4. Verify dates use ISO 8601 format with `Z` suffix
5. Verify UUIDs are valid v4 format

### Authentication and authorization (401/403)

**Common causes:**

* Missing `Authorization` header
* Expired or revoked token
* Token does not grant access to the requested endpoint

**Resolution steps:**

1. Confirm that Access Manager is enabled in your environment
2. Verify the token is present in the `Authorization` header
3. Request a new token if the current one has expired
4. Check that the token's scope includes the required permissions

### Resource not found (404)

**Common causes:**

* Incorrect resource ID in the URL path
* Resource was soft-deleted
* Resource belongs to a different organization or ledger

**Resolution steps:**

1. Verify the ID format (must be a valid UUID)
2. List resources to confirm the ID exists
3. Check that you are using the correct `organizationId` and `ledgerId` path parameters

### Conflict errors (409)

**Common causes:**

* Creating a resource with a name that already exists (e.g., duplicate ledger name, duplicate rule name)
* Attempting an operation that has already been completed (e.g., duplicate transaction)

**Resolution steps:**

1. Read the error message to identify which field caused the conflict
2. Use a different value (e.g., rename) or retrieve the existing resource instead
3. For idempotent operations, verify the existing resource matches your intent

### Rate limiting (429)

**Common causes:**

* Too many requests in a short period

**Resolution steps:**

1. Implement exponential backoff with jitter
2. Reduce the frequency of API calls
3. Batch operations where possible

### Server and timeout errors (500/502/503/504)

**Common causes:**

* Temporary service disruption
* High load on the platform
* Upstream dependency unavailable

**Resolution steps:**

1. Retry with exponential backoff (1s, 2s, 4s)
2. If the error persists after 3–5 retries, contact support
3. Log the full error response (including `code`) for support escalation

## Service-specific error lists

***

Each Lerian service publishes a complete list of its error codes. Use these references to look up specific error codes:

| Service             | Error list                                                                              |
| ------------------- | --------------------------------------------------------------------------------------- |
| Midaz               | [Midaz error list](/en/reference/midaz/error-list)                                      |
| Access Manager      | [Access Manager error list](/en/reference/access-manager/access-manager-error-list)     |
| CRM                 | [CRM error list](/en/reference/midaz/crm/crm-error-list)                                |
| Fees Engine         | [Fees Engine error list](/en/reference/midaz/plugins/fees-engine/fee-engine-error-list) |
| Bank Transfer (TED) | [TED error list](/en/reference/midaz/plugins/ted/ted-error-list)                        |
| Reporter            | [Reporter error list](/en/reference/reporter/reporter-error-list)                       |
| Tracer              | [Tracer error list](/en/reference/tracer/tracer-error-list)                             |

## Best practices

***

### 1. Use error codes for programmatic handling

Error codes are stable identifiers designed for automation. Map specific codes to resolution paths in your integration:

```
if error.code == "TRC-0100":
    # Rule not found — verify rule ID
elif error.code.startswith("TRC-01"):
    # Rule-related error — check rule configuration
elif error.code.startswith("TRC-0"):
    # Tracer validation error — check request format
```

### 2. Log errors with context

Include the full error response, the request that triggered it, and the timestamp. This makes support escalation faster and debugging more effective.

### 3. Handle field-level errors

When the response includes a `fields` object, surface those specific messages to your users rather than showing a generic error.

### 4. Implement circuit breakers for integrations

If you receive repeated `500`, `502`, or `503` errors, use a circuit breaker pattern to temporarily stop calling the failing service and prevent cascading failures.

### 5. Stay updated

Review the error list pages periodically. New error codes may be added as services evolve.
