> ## 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

> How to interpret, classify, and resolve errors returned by Lerian APIs.

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) |
| PIX                 | [PIX error list](/en/reference/midaz/plugins/indirect-pix/indirect-pix-btg-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.
