Límites y conmutación por error
Límites de peticiones y concurrencia por clave, colas breves de capacidad y conmutación automática entre canales. Códigos de estado y cómo reintentar bien.
Que los tokens sean más baratos solo sirve si las peticiones llegan a su destino. Entre tu petición y el modelo hay tres cosas: los límites que eliges para tu clave, la capacidad de los canales que sirven el modelo y la salud de esos canales. El gateway resuelve por su cuenta la mayoría de problemas de capacidad y salud, esperando un poco y reintentando en otro sitio. Cuando no puede, ves un 429 o un 502 breve y reintentable.
Conmutación automática por error#
Cuando un canal falla, la petición se reintenta en otro canal del mismo grupo de canales, con un máximo de tres intentos en total. Se reintenta cuando un canal:
- agota el tiempo, no responde o contesta
408,409,425,429o cualquier5xx; - rechaza la petición por un motivo suyo, no tuyo;
- falla durante un stream antes del primer token (consulta Streaming).
Las conversaciones nuevas se reparten entre los canales que sirven un modelo. Un canal que da más errores de lo normal, o va mucho más lento de lo habitual, recibe menos conversaciones nuevas hasta que se recupera. Uno que falla una y otra vez sale de la rotación durante un tiempo, y las conversaciones fijadas a él pasan a un canal sano.
Dos situaciones nunca se reintentan:
- Tu petición no es válida. Si el modelo la rechaza con
400,404,413o422, otro canal también la rechazaría. Recibes el estado y el motivo. - La salida ya empezó. Tras el primer token, la petición queda ligada a su canal. Un fallo posterior llega como evento de error dentro del stream.
Espera por capacidad#
Cada canal atiende un número limitado de peticiones a la vez. Si el canal que usaría una petición está lleno, el gateway prueba los demás canales del modelo. Si todos están llenos, la petición entra en la cola del canal que debería liberarse antes.
El tiempo total de espera tiene un tope de 10 segundos. Una petición admitida indica su espera en x-halfoff-queued-ms. Una que no se admite falla con 429, el mensaje All upstream capacity for this model is busy. Retry shortly. y una cabecera retry-after.
Esperar no cuesta nada; la facturación solo empieza cuando la petición se ejecuta, y una petición rechazada con 429 nunca se cobra.
Límites en tus propias claves#
Puedes poner a cada clave un tope de Solicitudes por minuto y otro de Máx. de solicitudes simultáneas en Limits & restrictions, al crearla o editarla en Claves de API. Ninguno está activo por defecto.
| Límite | Qué cuenta |
|---|---|
| Requests per minute | Peticiones iniciadas en los últimos 60 segundos, en ventana móvil. |
| Max concurrent requests | Peticiones en curso, incluidos los streams abiertos hasta que terminan. |
Una petición que supera un límite espera hasta 2 segundos a que quede hueco. Si no lo hay, falla con 429, el mensaje This API key has reached its rate or concurrency limit. y retry-after en segundos. Dar a cada carga de trabajo su propia clave con sus propios límites evita que una tarea deje sin recursos a otra. El resto de ajustes de clave está en Claves de API.
Códigos de estado#
| Estado | Causa | Qué hacer |
|---|---|---|
429 | Tope de RPM o de concurrencia de la clave. Incluye retry-after. | Espera retry-after segundos o sube el tope. |
429 | Toda la capacidad del modelo estuvo ocupada 10 segundos. Incluye retry-after. | Espera retry-after segundos y reintenta. |
429 | Todos los canales probados devolvieron límite de frecuencia. Mensaje Upstream capacity for this model is busy. Retry shortly. | Reintenta con backoff. |
502 | Todos los canales probados fallaron. Mensaje The model provider returned an error. Please retry. | Reintenta con backoff. |
500 | Error inesperado del gateway. | Reintenta una o dos veces; si persiste, contacta con soporte con el x-halfoff-request-id. |
402 | Saldo igual o inferior a cero, o límite de gasto de la clave alcanzado. | Recarga o sube el límite. No reintentes. |
400, 404, 413, 422 | Petición no válida o demasiado grande, o id de modelo desconocido. | Corrige la petición. No reintentes. |
401, 403 | Clave ausente, revocada o caducada, o sin permiso para ese modelo. | Corrige la clave. No reintentes. |
El tipo de error sigue tu API: rate_limit_error (Anthropic), rate_limit_exceeded (OpenAI) o RESOURCE_EXHAUSTED (Gemini) para 429, y api_error (UNAVAILABLE en Gemini) para 502. Todos los códigos están en Errores.
Reintentar desde tu código#
Cuando ves un 429 o un 502, el gateway ya ha probado varios canales. Reintenta unas cuantas veces más con backoff exponencial y jitter, y respeta retry-after cuando venga.
Los SDK de Anthropic y OpenAI ya reintentan 408, 409, 429 y 5xx dos veces por defecto. Para procesos por lotes largos, permite más:
import os
from openai import OpenAI
client = OpenAI(base_url="https://halfoff.dev/v1", api_key=os.environ["HALFOFF_API_KEY"], max_retries=6)Con HTTP directo, aplica tú la misma política:
# --retry cubre 429 y 5xx y respeta retry-after
curl --retry 6 --retry-max-time 180 https://halfoff.dev/v1/chat/completions \
-H "Authorization: Bearer $HALFOFF_API_KEY" \
-H "content-type: application/json" \
-d '{"model": "gpt-5.6-luna", "messages": [{"role": "user", "content": "Clasifica: \"la app se cierra al iniciar sesión\""}]}'Con streams, reintenta solo si el error llega antes de cualquier contenido. Un stream que se rompe a medias ya se ha cobrado por su salida parcial, así que decide si te quedas con ella o pides de nuevo la respuesta completa.
Saldo y límites de gasto#
Antes de ejecutarse, cada petición comprueba tu saldo y el límite de gasto de la clave. Si el saldo es igual o inferior a cero, o la clave agotó su límite, recibes 402 con Insufficient balance. Top up at the dashboard. o This API key has reached its spend limit. El tipo de error es insufficient_quota (OpenAI), billing_error (Anthropic) o RESOURCE_EXHAUSTED (Gemini).
La comprobación se hace al inicio de la petición y el cargo se liquida unos segundos después de que termine. Una petición que empieza con saldo positivo siempre llega hasta el final, así que el saldo puede quedar ligeramente por debajo de cero; tu siguiente recarga cubre la diferencia. Consulta Facturación.