# Códigos de error

Un único formato de error para todo, qué significa cada código y qué hacer cuando aparece.

> https://nezhagate.com/es/docs/guide/errors

## Formato de error

Cuando un endpoint de `/v1` falla, responde con un estado 4xx / 5xx y un JSON como el del ejemplo de abajo: `message` es para personas, `type` es la categoría general, `code` es un identificador estable y legible por máquina, y `param` indica el campo que causó el error (`null` si no hay ninguno). Decide según el estado HTTP y `code`, nunca según el texto de `message`: puede estar en inglés, en chino o en ambos, y su redacción cambia.

```
{
  "error": {
    "message": "Insufficient balance — please top up",
    "type": "insufficient_quota",
    "code": "insufficient_quota",
    "param": null
  }
}
```

Los endpoints `/anthropic` usan el formato propio de Anthropic, sin `code` ni `param`; decide según el estado HTTP y `error.type`:

```
{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "message": "model: gpt-5.5"
  }
}
```

- Algunos errores traen campos adicionales en el nivel superior, como `attempts` cuando todas las líneas están ocupadas o `retry_after` cuando no hay ninguna línea disponible por un momento. Ignora cualquier campo que no conozcas.

- Cuando el proveedor del modelo rechaza una petición (por ejemplo, por un contexto demasiado largo), `message` contiene el texto del propio proveedor y `code` es el valor que dio el proveedor, o `invalid_request` si no dio ninguno.

## Estados HTTP de un vistazo

| HTTP | Cuándo aparece |
| --- | --- |
| **400** | Un parámetro incorrecto o un modelo desconocido (como `model_not_found`); `error.param` indica el campo. |
| **401** | Falta la clave, o es inválida o está desactivada (`missing_api_key`, `invalid_api_key`). |
| **402** | Saldo insuficiente, o la clave llegó a su presupuesto (`insufficient_quota`). |
| **403** | El modelo no está en la lista de modelos permitidos de esta clave, o la petición llega desde fuera de su lista de IP permitidas (`permission_denied`). |
| **404** | La ruta no existe; o el id del trabajo es desconocido, superó sus 3 días de registro o lo envió otra cuenta (`job_not_found`). |
| **429** | Superaste el límite por minuto de esta clave o la cuota diaria de un modelo gratuito, o todas las líneas del modelo están ocupadas (`rate_limit_exceeded`). Espera los segundos de `Retry-After` si viene, o unos segundos si no, y reintenta. |
| **502** | El proveedor falló o tardó demasiado y cambiar de línea no bastó; `code` indica el motivo, por ejemplo `upstream_timeout` o `upstream_unavailable`. No se cobra; puedes reintentar. |
| **503** | El modelo está en mantenimiento (`model_maintenance`) o hubo un fallo momentáneo de nuestro lado (`service_unavailable`). No se cobra; reintenta más tarde. |

## Todos los códigos de error

Los errores que devuelve la pasarela, por categoría. Un mismo estado HTTP puede corresponder a varios códigos, así que guíate por `code`.

### Autenticación y cuenta

| HTTP | code | Causa | Qué hacer |
| --- | --- | --- | --- |
| **401** | `missing_api_key` | Falta la cabecera `Authorization: Bearer`. Los endpoints `/v1` no leen `x-api-key`. | Añade `Authorization: Bearer YOUR_API_KEY`. |
| **401** | `invalid_api_key` | La clave no existe, se eliminó o está desactivada, o la cuenta está desactivada. | Revisa la clave en la página API Keys de la consola. |
| **402** | `insufficient_quota` | El saldo de la cuenta se agotó (está por debajo del saldo negativo permitido). | Recarga y reintenta. |
| **403** | `permission_denied` | La petición llega desde fuera de la lista de IP permitidas de la clave. | Llama desde una IP permitida o edita la lista en la consola. |

### Límites configurados en la clave

| HTTP | code | Causa | Qué hacer |
| --- | --- | --- | --- |
| **429** | `rate_limit_exceeded` | Se superó el límite de peticiones por minuto configurado en esta clave (contado sobre los últimos 60 segundos). Sin cabecera `Retry-After`. | Espera unos segundos y reintenta, o sube el límite de la clave en la consola. |
| **429** | `rate_limit_exceeded` | Se agotó la cuota diaria de un modelo gratuito (por cuenta y por día UTC). `message` puede sugerir un modelo de pago para usar en su lugar. | Vuelve a usarlo después de las 00:00 UTC o cambia a un modelo de pago. |
| **402** | `insufficient_quota` | Se agotó el presupuesto diario de la clave (por día UTC) o su límite total. | Vuelve a usarla al día siguiente o sube el límite en la consola. |
| **403** | `permission_denied` | El modelo no está en la lista de modelos permitidos de la clave. | Usa un modelo de la lista o edita la lista en la consola. |

### La propia petición

| HTTP | code | Causa | Qué hacer |
| --- | --- | --- | --- |
| **400** | `invalid_json` / `invalid_encoding` | El cuerpo de la petición no es un JSON válido; `invalid_encoding` si no está en UTF-8. | Revisa la sintaxis del JSON y la codificación. |
| **400** | `invalid_request` | Un parámetro no es válido: el cuerpo no es un objeto JSON, `n` no es un entero, no se puede leer una imagen o un vídeo de referencia (`message` indica cuál y por qué), `/v1/images/edits` no lleva imagen de referencia, la duración / resolución / proporción / cantidad de referencias de un vídeo está fuera del rango del modelo, etc. | Corrige lo que indica `message` y vuelve a enviar la petición. |
| **400** | `invalid_messages` / `invalid_role` / `invalid_max_tokens` | En una petición de chat, `messages` falta, está vacío o tiene un formato incorrecto, un `role` no es uno de los valores permitidos, o `max_tokens` no es un entero positivo. `param` indica el campo. | Corrige el campo que indica `param`. |
| **400** | `missing_prompt` | La petición a `/v1/images/generations` no lleva `prompt`. | Añade un `prompt`. |
| **400** | `unsupported_resolution` | El modelo no ofrece el nivel de resolución elegido (por ejemplo, la generación de imágenes de Grok no tiene 4K). | Elige otro nivel; la documentación de cada modelo indica sus niveles. |
| **400** | `invalid_callback_url` | `callback_url` no es una dirección http(s) pública o supera los 2000 caracteres. | Usa una dirección accesible desde internet. |
| **400** | `max_tokens_too_small` | Un modelo de razonamiento gastó todo `max_tokens` en razonar y no escribió ninguna respuesta (chat sin streaming). | Sube `max_tokens` y reintenta. |
| **404** | `not_found` | La ruta del endpoint no existe. | Revisa la ruta; la [referencia de la API](https://nezhagate.com/es/docs/api) lista todos los endpoints. |
| **404** | `job_not_found` | El id del trabajo es desconocido, superó sus 3 días de registro o lo envió otra cuenta; consultar un trabajo de imagen en el endpoint de vídeo (o al revés) también da este error. | Revisa el id del trabajo y el endpoint. El enlace del resultado se guarda 60 días y no le afecta que caduque el registro del trabajo. |

### Estado del modelo

| HTTP | code | Causa | Qué hacer |
| --- | --- | --- | --- |
| **400** | `model_not_found` | El ID del modelo está mal escrito, falta `model`, o el modelo no se puede usar en este endpoint (por ejemplo, un modelo de chat en el endpoint de imágenes). | Usa un ID de modelo de `GET /v1/models` o de la [referencia de la API](https://nezhagate.com/es/docs/api). |
| **400** | `model_disabled` | El modelo se retiró. | Cambia a otro modelo; si existe un modelo que lo reemplaza, las páginas del modelo antiguo redirigen a él. |
| **400** | `model_coming_soon` | El modelo está anunciado, pero todavía no admite llamadas. | Espera el anuncio de lanzamiento. |
| **503** | `model_maintenance` | El modelo está en mantenimiento y no acepta peticiones; mientras tanto, ningún otro modelo responde en su lugar. | Reintenta cuando termine el mantenimiento; consulta el [estado del servicio](https://nezhagate.com/es/status). |

### Capacidad y retenciones

| HTTP | code | Causa | Qué hacer |
| --- | --- | --- | --- |
| **402** | `insufficient_quota` | No hay saldo suficiente para retener el importe de esta petición. La pasarela retiene primero el coste máximo posible de la petición, así que una ráfaga de llamadas simultáneas también puede provocarlo. | Si se debe a una ráfaga, espera unos segundos y reintenta; si no, recarga. |
| **429** | `rate_limit_exceeded` | Todas las líneas de este modelo están ocupadas y la petición no se envió. Solo en los endpoints de chat: los trabajos de imagen y vídeo nunca se rechazan, sino que esperan en cola. Los endpoints compatibles con OpenAI añaden `Retry-After`. | Espera los segundos que indica `Retry-After` y reintenta. |
| **503** | `service_unavailable` | Un fallo temporal de nuestro lado, por ejemplo al guardar un archivo de referencia; `/v1/responses` también responde 503, con `Retry-After`, cuando no hay ninguna línea disponible por un momento. | Reintenta en breve. |

### Errores del proveedor (endpoints de chat)

Cuando falla un endpoint de chat (`/v1/chat/completions`, `/v1/responses`, `/anthropic/v1/messages`), la pasarela primero reintenta en otras líneas y solo devuelve uno de estos errores cuando todas han fallado. Ninguno se cobra.

| HTTP | code | Causa | Qué hacer |
| --- | --- | --- | --- |
| **502** | `upstream_timeout` | Una línea agotó el tiempo de espera, incluido el caso de tardar demasiado en enviar el primer token. | Reintenta; para respuestas largas, usa `stream: true`. |
| **502** | `upstream_unavailable` | Una línea falló o no está disponible por el momento. | Reintenta en breve. |
| **502** | `upstream_busy` | El proveedor del modelo está limitando las peticiones. Un 429 del proveedor nunca te llega como 429; en su lugar recibes este 502. | Reintenta en breve. |
| **502** | `upstream_connection_error` | Se cortó la conexión con el proveedor del modelo. | Reintenta. |
| **502** | `empty_completion` | El proveedor del modelo devolvió un contenido vacío. No es una valoración de tu contenido. | Reintenta. |
| **502** | `upstream_error` | Una línea respondió con una frase de error en lugar de una respuesta. | Reintenta. |
| **400** | `content_filter` | El modelo procesó la petición pero no devolvió nada, normalmente porque el contenido activó la política de seguridad del proveedor. | Ajusta el prompt y reintenta; el mismo prompt suele volver a rechazarse. |
| **502** | `upstream_prompt_filter` | La verificación previa del proveedor bloqueó el prompt. No es una valoración del modelo. | Reintenta en breve o cambia un poco la redacción. |
| **4xx** | — | El proveedor del modelo rechazó la petición (por ejemplo, por un contexto demasiado largo o un parámetro no admitido); el estado y `message` se transmiten tal como los envió el proveedor, y `code` es el valor del proveedor. | Modifica la petición según lo que indique `message`. |

### Los endpoints de Anthropic

- `error.type` sigue los valores estándar de Anthropic según el estado: 400 `invalid_request_error`, 401 `authentication_error`, 402 `billing_error`, 403 `permission_error`, 404 `not_found_error`, 429 `rate_limit_error` (`overloaded_error` cuando todas las líneas están ocupadas), 502 `api_error`, 503 `overloaded_error` (`api_error` mientras el modelo está en mantenimiento).

- `/anthropic` solo acepta modelos Claude; con cualquier otro modelo responde 404 `not_found_error`.

- `max_tokens` es obligatorio y no puede ser 0; si no, recibes un 400.

## Trabajos fallidos (imagen y vídeo)

Cuando un trabajo de imagen o vídeo falla después de haber sido aceptado, el endpoint del trabajo sigue respondiendo HTTP 200 con `status` `failed`; el motivo está en `error` y `error.code` es uno de los valores de abajo. Los créditos retenidos para el trabajo vuelven a tu saldo. Con un webhook recibes `image.failed` / `video.failed` con el mismo contenido.

| code | Cuándo aparece | Qué hacer |
| --- | --- | --- |
| `content_policy` | Vídeo: el prompt, una referencia, o la imagen o el sonido generados no superaron la revisión de contenido (`param` es `audio` cuando lo que se marcó fue el sonido). | Reescribe el prompt o cambia la referencia antes de volver a enviarlo; la misma entrada se rechaza otra vez. |
| `moderation_blocked` | Imagen: el sistema de seguridad del proveedor del modelo rechazó el prompt o una imagen de referencia (el código también puede ser `content_policy_violation`). | Reescribe el prompt o cambia la referencia; si se reenvía sin cambios, normalmente se vuelve a rechazar. |
| `render_failed` | Vídeo: esta vez no salió ningún clip; suele ser algo puntual. | Volver a enviar la misma petición suele funcionar. |
| `invalid_material` | Vídeo: el proveedor encontró un problema en la entrada. Es un error genérico y a menudo puntual. | Primero reenvíalo tal cual; si se repite, revisa las referencias y la longitud del prompt. |
| `render_timeout` | Vídeo: la cola o el render tardaron demasiado y el proveedor abandonó el trabajo. | Vuelve a enviarlo. |
| `wait_timeout` | Vídeo: no llegó ningún clip dentro del tiempo máximo de espera que permite la línea. | Vuelve a enviarlo. |
| `upstream_unstable` | Vídeo: la conexión se cortó durante el render. | Vuelve a enviarlo. |
| `result_fetch_failed` | El vídeo se generó, pero su descarga o almacenamiento falló una y otra vez de nuestro lado. | Vuelve a enviarlo. |
| `invalid_request` | Vídeo: la línea no acepta esta combinación de parámetros (por ejemplo, duración, proporción y resolución). | Ajusta los parámetros según indica `message` y vuelve a enviarlo. |
| `upstream_error` | Cualquier otro fallo: se probaron todas las líneas, el trabajo esperó 15 minutos sin empezar, el proveedor lo rechazó sin dar motivo, etc.; `message` indica cuál. | Volver a enviarlo suele funcionar. |

[Guía completa de trabajos asíncronos →](https://nezhagate.com/es/docs/guide/async-jobs)

## Errores a mitad de un streaming

- Una vez que una petición con streaming ha respondido HTTP 200 y ha empezado a enviar datos, un error posterior ya no puede cambiar el estado: o llega como un evento de datos con `error`, o el streaming simplemente termina.

- Comprueba que el streaming está completo: en el formato de OpenAI, busca un `finish_reason` y `data: [DONE]`; en el de Anthropic, `message_stop`. Si no aparecen, trata el streaming como cortado.

- Un streaming que se corta se cobra por el uso generado hasta ese momento; consulta [Facturación y reembolsos](https://nezhagate.com/es/docs/guide/billing).

## ¿Se cobran los errores?

- Una petición que devuelve un error nunca se cobra: o el error llega antes de cualquier cargo, o se devuelve toda la retención.

- Los trabajos de imagen y vídeo fallidos se reembolsan íntegros.

- La única excepción es un streaming que ya empezó: si se corta, pagas el uso generado hasta ese momento.

## Cuándo reintentar

Ante un 4xx, corrige primero la petición (con un 402, recarga; con un 429, espera un poco); los errores 5xx y los tiempos de espera agotados se pueden reintentar tal cual, con espera exponencial, esperando lo que indique `Retry-After` cuando venga.

[Estrategia de reintentos y código de ejemplo →](https://nezhagate.com/es/docs/guide/rate-limits#retry)
