# Errores

> El formato de los errores de la API de OpenWAF, sus estados HTTP y cada código de error estable con su significado.

Los errores responden un estado HTTP y un cuerpo JSON:

```json
{
  "error": {
    "code": "version_conflict",
    "message": "the configuration changed: the current version is 13"
  },
  "current_version": 13
}
```

| Campo | Significado |
|---|---|
| `error.code` | Código estable: es el que debe usar tu código. |
| `error.message` | Explicación para personas; su texto puede cambiar. |
| `error.field` | Campo que no pasó la validación, si lo hay (p. ej. `ttl`, `records[3].content`). |

Algunos códigos añaden campos junto a `error`: `current_version` (`version_conflict`), `hostnames` (`missing_certs`), `plan` (`merge_not_equivalent`).

## Estados HTTP

| Estado | Significado |
|---|---|
| `200`, `201` | Correcto. Con `dry_run=1`, `200` lleva el plan del cambio. |
| `204` | Correcto, sin cuerpo. |
| `400` | Petición mal formada: JSON no válido, campo desconocido, parámetro de consulta no válido. |
| `401` | Token ausente, no válido, caducado o revocado. |
| `403` | El rol o los límites del token no permiten la operación. |
| `404` | El recurso no existe o el token no lo puede ver. |
| `409` | El estado actual no permite el cambio. |
| `412` | `If-Match` no coincide con la versión actual. |
| `413` | El cuerpo es demasiado grande. |
| `422` | Error de validación o falta el motivo del cambio. |
| `428` | La operación exige `If-Match`. |
| `429` | Demasiadas peticiones: espera los segundos de `Retry-After`. |
| `502`, `503` | Una dependencia no respondió o la función no está disponible: reinténtalo más tarde. |

## Códigos de error

| Código | Estado | Descripción |
|---|---|---|
| `bad_request` | `400` | Petición mal formada: JSON no válido, campo desconocido o parámetro no válido. |
| `unauthorized` | `401` | Token ausente, no válido, caducado o revocado. |
| `forbidden` | `403` | El rol o los límites del token no permiten la operación. |
| `token_scope` | `403` | Un token que solo puede purgar la caché ha llamado a otra ruta. |
| `feature_disabled` | `403` | La función (egress) no está activada en la organización. |
| `zone_limit` | `403` | La organización ha alcanzado su límite de zonas. |
| `org_suspended` | `403` | La organización está suspendida; se rechazan las escrituras. |
| `org_pending_approval` | `403` | La organización está pendiente de aprobación; se rechazan las escrituras. |
| `not_found` | `404` | El recurso no existe o el token no lo puede ver. |
| `host_not_in_zone` | `404` | El nombre no es la zona ni está por debajo de ella. |
| `conflict` | `409` | El estado actual no permite el cambio (p. ej. una zona desactivada, el último owner, un nombre repetido). |
| `zone_exists` | `409` | El dominio ya está dado de alta. |
| `zone_overlaps` | `409` | El dominio es padre o subdominio de una zona de otra organización o de otro cliente. |
| `zone_not_active` | `409` | La zona no está activa. |
| `zone_not_external` | `409` | La operación es solo para zonas externas. |
| `zone_merged` | `409` | La zona está fusionada en otra y es de solo lectura hasta que se separe. |
| `merge_not_equivalent` | `409` | La fusión cambiaría cómo se sirve algún nombre; el cuerpo lleva el plan. |
| `merge_not_reversible` | `409` | La zona no está fusionada o su padre ha cambiado desde la fusión. |
| `missing_certs` | `409` | Algunos sitios quedarían sin certificado válido; el cuerpo lista los nombres. |
| `already_member` | `409` | La persona ya es miembro de la organización. |
| `owner_of_zones` | `409` | El cambio dejaría zonas sin dueño. |
| `client_has_zones` | `409` | El cliente aún tiene zonas; muévelas o bórralas antes. |
| `host_taken` | `409` | El nombre lo usa otra organización. |
| `target_in_use` | `409` | Algún agente de egress aún permite el destino. |
| `version_conflict` | `412` | `If-Match` no coincide con la versión actual; el cuerpo lleva `current_version`. |
| `too_large` | `413` | El cuerpo o el fichero es demasiado grande. |
| `invalid` | `422` | Error de validación; `field` indica el campo. |
| `reason_required` | `422` | Falta la cabecera `X-Change-Reason` o no es válida. |
| `if_match_required` | `428` | La operación exige `If-Match`. |
| `rate_limited` | `429` | Demasiadas peticiones; espera los segundos de `Retry-After`. |
| `too_many_streams` | `429` | Demasiados streams de eventos abiertos en la organización. |
| `dns_backend` | `502` | El servicio DNS rechazó el cambio; reinténtalo más tarde. |
| `dns_unavailable` | `502` | El DNS público no respondió. |
| `credential_store` | `502` | El almacén de credenciales rechazó la escritura; reinténtalo más tarde. |
| `unavailable` | `503` | La función no está disponible ahora; reinténtalo más tarde. |
| `busy` | `503` | Demasiadas comprobaciones en curso; reinténtalo en unos segundos. |
| `internal` | `500` | Error inesperado; reinténtalo y, si persiste, escribe a support@openwaf.dev. |
