# Solución de problemas

> Cada error que devuelve la pasarela OpenWAF Egress (401, 403, 404, 413, 502 y otros), qué lo causa y cómo arreglarlo.

Cada error que devuelve la propia pasarela es JSON con un código en `error` y un `message` (en inglés). Los errores del proveedor llegan sin cambios; los de la pasarela llevan siempre uno de los códigos de abajo. La pasarela también escribe cada rechazo en la salida estándar (`docker logs openwaf-egress`).

```json
{"error": "egress_blocked", "message": "Agent \"my-support-agent\" is not permitted to access target \"openai\""}
```

> **Nota: Pasarela alojada**
>
> En `egress.openwaf.dev` algunas respuestas cambian (el agente se identifica por su token, un destino sin clave se rechaza, `503 policy_unavailable`): mira la [referencia del egress alojado](https://developers.openwaf.dev/es/egress/cloud/reference/#gateway-errors).


## Todos los códigos de error

| Estado | `error` | Causa |
|---|---|---|
| 400 | `body_read_error` | No se pudo leer el cuerpo de la petición (el cliente se desconectó o la transferencia se cortó). |
| 401 | `unauthorized_agent` | Ningún agente coincide: el nombre de la URL o de `X-OpenWAF-Agent` no está en `agents` o, en `/v1/proxy/…`, ningún agente tiene el token enviado. |
| 401 | `token_required` | El agente tiene `token` y la petición no lleva cabecera `Authorization`. |
| 401 | `invalid_token` | El valor de `Authorization: Bearer` no es el `token` del agente. |
| 403 | `egress_blocked` | El destino existe pero no está en los `allowed_targets` del agente. |
| 403 | `ssrf_blocked` | El `host` del destino resuelve a una dirección privada o reservada, o no resuelve. |
| 403 | `injection_detected` | Un detector de inyección de prompt ha saltado con el cuerpo (`enforce_injection`). |
| 403 | `data_leak_blocked` | Un patrón de fuga de datos ha saltado con el cuerpo (`block_dlp`). |
| 404 | `invalid_route` | La ruta no es `/v1/agent/<agente>/proxy/<destino>/…`, `/v1/proxy/<destino>/…` ni `/health`. |
| 404 | `unknown_target` | El alias del destino no está en `targets`. |
| 413 | `body_too_large` | El cuerpo pasa de 8 MiB o, con la inspección activada, su texto fuera de los medios en línea pasa de 1 MiB. |
| 500 | `invalid_upstream_url`, `request_creation_failed` | La `base_url` del destino no se puede interpretar, o no se puede construir la petición de salida. |
| 502 | `credential_resolution_failed` | No se pudo leer la clave de OpenBao o Vault. |
| 502 | `upstream_error` | No se pudo llegar al proveedor (DNS, conexión, TLS o tiempo agotado). |

## 401: el agente no se identifica

- `unauthorized_agent`: compara el `<agente>` de la URL base con las claves de `agents`. Se distinguen mayúsculas y minúsculas.
- `token_required`: el SDK tiene que enviar la clave en `Authorization: Bearer`. Si la envía en otra cabecera (por ejemplo `x-api-key`), la pasarela no la ve.
- `invalid_token`: el marcador del agente no coincide con el `token` de la configuración. Recuerda que hay que reiniciar después de editar el fichero.

## 403: la petición se ha rechazado

**`egress_blocked`**: añade el alias del destino a los `allowed_targets` del agente.

**`ssrf_blocked`**: el mensaje dice qué dirección se ha rechazado, por ejemplo `destination IP 169.254.169.254 is private or reserved`. Un nombre del proveedor que en tu red resuelve a una dirección privada (DNS partido, un proxy local) también se rechaza. Un error de resolución acaba aquí igualmente: revisa el DNS desde dentro del contenedor.

**`injection_detected`**: la respuesta enumera cada detección con el `ID` del detector, su `Label` y el `Snippet` encontrado:

```json
{"agent":"my-support-agent","detections":[{"ID":"pi.override.en","Label":"Instruction override","Snippet":"Ignore all previous instructions"}],"error":"injection_detected","message":"Request body contains prompt injection or adversarial pattern","target":"openrouter"}
```

Mira el fragmento: es el texto que ha saltado, de 160 bytes como mucho. Si venía de un documento o una página web que leyó el agente, la pasarela ha hecho su trabajo al no dejarlo pasar. En la v0.1.1 los detectores no se pueden desactivar de uno en uno; para un agente que tenga que procesar ese tipo de texto, pon `enforce_injection` a `false` solo en ese agente.

**`data_leak_blocked`**: la respuesta enumera cada `type` (`credit_card`, `private_key`, `api_key`) con una descripción. Los números de tarjeta solo se muestran con los cuatro primeros y los cuatro últimos dígitos. Quita esos datos del prompt, o pon `block_dlp` a `false` en ese agente.

## 413: el cuerpo es demasiado grande

La pasarela nunca recorta un cuerpo ni reenvía una parte sin inspeccionar. Con `enforce_injection` o `block_dlp` activados, el texto tiene que caber en 1 MiB. Los medios en línea no cuentan: las URI `data:image/…;base64,…` (también de audio y vídeo) y los miembros JSON `"data"` con al menos 1 KiB de base64 (`input_audio` de OpenAI, `inlineData` de Gemini, fuentes base64 de Anthropic). Envía los ficheros grandes por URL o con la API de ficheros del proveedor, o divide la petición. Ningún cuerpo puede pasar de 8 MiB.

## 502: falla OpenBao o el proveedor

**`credential_resolution_failed`**: la línea del registro dice qué secreto ha fallado, sin su valor:

```text
[EGRESS] Failed resolving secret agents/support:OPENROUTER_API_KEY for agent my-support-agent: vault error 403 reading agents/support
```

- `obtaining vault token: approle login failed with status …`: `role_id` o `secret_id` incorrectos, o el ID secreto ha caducado.
- `vault error 403`: la política del AppRole no permite `read` sobre `<kv_mount>/data/<path>`, a menudo porque `kv_mount` o `path` están mal. Con KV v2 el montaje no forma parte de `path`.
- `vault error 404`: no hay ningún secreto en esa ruta.
- `key "…" not found in path "…"`: el secreto existe pero no tiene un campo con ese nombre.
- Un error de conexión o de certificado: revisa `addr` y `ca_file`, y que `/health` diga `"openbao": true`.

**`upstream_error`**: el mensaje incluye el error. Revisa la `base_url` del destino, el DNS y la salida a internet del contenedor. La pasarela espera hasta 5 minutos las cabeceras de respuesta del proveedor y 15 minutos un intercambio entero, con el cuerpo en streaming.

## El proveedor responde 401 o 403

El error es del proveedor y llega tal cual. Causas habituales:

- El destino no tiene entrada en el `credential_mapping` del agente, así que la petición llegó al proveedor sin clave.
- La clave de OpenBao es incorrecta, está revocada o se rotó hace menos de cinco minutos (la pasarela guarda los secretos en caché cinco minutos).
- La `auth_header` o el `auth_prefix` del destino no son los que espera el proveedor (Anthropic: `x-api-key` sin prefijo; Gemini: `x-goog-api-key`). Las claves en la cadena de consulta (`?key=`) no se inyectan.

## El agente recibe un 3xx

La pasarela no sigue redirecciones; el `3xx` del proveedor llega al agente tal cual. Apunta `base_url` a la URL final que documenta el proveedor (por ejemplo `https://` en lugar de `http://`).

## /health dice "openbao": false

O no hay `openbao.addr`, o la pasarela no ha recibido `200` ni `429` de `<addr>/v1/sys/health` en tres segundos: el servidor está sellado o no se llega a él, o su certificado no es de confianza (pon `ca_file`). Las peticiones a destinos con `credential_mapping` fallarán con `502` hasta que se arregle.

Escrito a partir de [github.com/openwaf-dev/egress@v0.1.1](https://github.com/openwaf-dev/egress/tree/v0.1.1).
