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

# Errores

> Una forma de error, un code estable, y qué hacer con cada tipo.

Cada respuesta que no es 2xx tiene el mismo body:

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_failed",
    "message": "email is not a valid address.",
    "param": "email",
    "detail": [
      { "field": "email", "message": "value is not a valid email address", "code": "value_error" }
    ],
    "request_id": "req_8f2c...",
    "documentation_url": "https://docs.chatsailer.com/guides/errors"
  }
}
```

Bifurca por `type` para el control de flujo y por `code` para el manejo
específico. Ambos son estables; `message` está escrito para humanos y puede
reformularse.

Siempre loguea `request_id`. Se ecoa en el header de respuesta `X-Request-ID`,
y citarlo nos deja encontrar tu petición exacta.

## Tipos

| Type                    | HTTP     | Qué significa                                            | Qué hacer                                                                               |
| ----------------------- | -------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| `invalid_request_error` | 400, 422 | La petición está malformada o falla la validación        | Arregla la petición. Lee `detail` para los campos que fallan. No reintentes sin cambios |
| `authentication_error`  | 401      | Token faltante, malformado, revocado o expirado          | Revisa el header `Authorization`. No reintentes sin cambios                             |
| `permission_error`      | 403      | Autenticado, pero no permitido                           | Suele ser un scope faltante, o una política de write del workspace. Ver abajo           |
| `not_found_error`       | 404      | No existe ese registro, **o** está fuera de tu workspace | No reintentes                                                                           |
| `conflict_error`        | 409      | Conflicto con el estado existente, p. ej. un duplicado   | Reconcilia, luego reintenta                                                             |
| `rate_limit_error`      | 429      | Demasiadas peticiones                                    | Haz backoff y reintenta — ver abajo                                                     |
| `api_error`             | 5xx      | Algo se rompió de nuestro lado                           | Reintenta con backoff. Si persiste, mándanos el `request_id`                            |

<Note>
  Un 404 no distingue "no existe" de "pertenece a otro workspace". Es
  deliberado: distinguirlos le permitiría a cualquiera sondear ids de
  registros entre workspaces.
</Note>

## Scopes faltantes

Un 403 de un chequeo de scope nombra exactamente lo que falta, para que no
tengas que adivinar:

```json theme={null}
{
  "error": {
    "type": "permission_error",
    "code": "insufficient_scope",
    "message": "This endpoint requires the contacts:write scope."
  }
}
```

Un 403 que *no* es `insufficient_scope` suele significar política de write del
workspace — por ejemplo, una entidad espejada desde un CRM externo. Llama
`GET /v1/capabilities` para ver qué entidades puedes escribir.

## Reintentos

Reintenta `rate_limit_error` y `api_error`. No reintentes errores 4xx sin
cambios; van a fallar igual.

```python theme={null}
for attempt in range(5):
    response = httpx.request(method, url, headers=headers, json=body)
    if response.status_code < 400:
        return response.json()
    if response.status_code not in (429, 500, 502, 503, 504):
        raise SailerError(response.json()["error"])
    time.sleep(2 ** attempt)
```

Usa backoff exponencial con jitter. Reintentar de inmediato durante un rate
limit lo extiende.
