Errores sobre los que puedes actuar
Todo error de Hyperouter usa el objeto de error de OpenAI y un estado HTTP equivalente. El código que ya gestiona los errores de OpenAI gestiona la mayoría de estos. Esta guía cubre lo que merece una acción y lo que no, y termina con un bucle de reintentos.
El objeto de error
{
"error": {
"message": "n must be an integer from 1 to 128",
"type": "invalid_request_error",
"code": "invalid_body",
"param": "n"
}
}
| Campo | Significado |
|---|---|
message | Una frase que dice qué está mal. No la analices. |
type | La clase de error. |
code | Un identificador estable de la causa. Compara por este campo. |
param | El campo de la solicitud que falla, o null. |
Algunos errores añaden generation_id: el id de un trabajo que sigue en curso o que ya se ejecutó. Consúltalo con GET /v1/generations/{id}.
Estados que conviene gestionar
| Estado | Qué significa | Qué hacer |
|---|---|---|
400 | La solicitud no es válida. code indica la causa y param el campo. | Corrige la solicitud. No la reintentes sin cambios. |
401 | La clave de API falta o no es válida. | Revisa la clave. |
402 | insufficient_credits: tu saldo, o el límite de la clave, no puede cubrir lo máximo que podría costar la solicitud. | Recarga, o sube el límite de la clave. |
403 | La cuenta está suspendida, o una función o un modelo no está habilitado para ella. | Abre un ticket de soporte. |
404 | No existe ese id, es el id de otra cuenta, o es un vídeo pasado su expires_at. | No reintentes. |
409 | No está en un estado que permita la llamada, o hay un conflicto de Idempotency-Key. | Consulta reintentar con seguridad. |
429 | Todos los proveedores están a su capacidad, o tu cuenta supera sus límites de velocidad. | Espera Retry-After y reintenta. |
500, 501 | Hyperouter falló, o el endpoint no está implementado. No se factura. | Reintenta un 500 con cuidado, como se explica abajo. |
503 | Un proveedor falló o no respondió a tiempo. | Reintenta, como se explica abajo. |
Tres códigos que encontrarás
insufficient_credits(402). En chat, el mensaje indica cuántos tokens puedes permitirte. Bajarmax_tokensbaja lo máximo que puede costar la solicitud. Una recarga es una solicitud manual en el panel; GET /v1/credits te permite verlo venir.model_not_enabled(403). El modelo necesita que se conceda acceso a tu cuenta. Abre un ticket de soporte para solicitarlo. No se retiene nada ni se envía al proveedor.rate_limited(429). Tu cuenta supera sus solicitudes por minuto o sus solicitudes concurrentes. No se retiene ni se reenvía nada. La respuesta tiene un encabezadoRetry-Afteren segundos, y la sección de límites de velocidad enumera los niveles.
La misma familia incluye venue_busy (429): todos los proveedores de un modelo de chat superan su presupuesto de velocidad.
Por qué 503, y no 502 ni 504
Hyperouter nunca responde 502 ni 504. Te llegarían como una página simple de nuestra red perimetral, sin el cuerpo del error, así que no podrías leer code.
Donde una pasarela respondería con ellos, recibes 503 con el objeto de error habitual, y el estado de la pasarela en el encabezado de respuesta X-Upstream-Status: 502 cuando un proveedor falló, 504 cuando agotó el tiempo. El code indica qué tipo de fallo fue: all_venues_failed, upstream_error o timeout.
HTTP/2 503
x-upstream-status: 504
Lee X-Upstream-Status si quieres distinguir un fallo de un tiempo agotado. Para la mayoría del código, 503 y code bastan.
Cuándo no reintentar
Reintentar no siempre es seguro. Un reintento puede iniciar un segundo trabajo o un segundo cargo. Hyperouter marca esas respuestas con x-should-retry: false:
- el
503timeoutde una imagen síncrona. El trabajo continúa y se factura si tiene éxito. Consulta periódicamenteerror.generation_iden su lugar; - un
500después de crear un trabajo; 409idempotency_key_reusedeidempotency_key_replayed.
En chat, un proveedor que ha aceptado una solicitud puede estar ejecutándola. Si después deja de responder, la solicitud no se envía a otro proveedor: la respuesta es 503 con el código timeout o upstream_error, y se factura sobre su retención. Consúltala con GET /v1/generations/{id} antes de decidir enviarla de nuevo.
Un bucle de reintentos con espera creciente
Reintenta 429 y 503, respeta Retry-After, abandona ante x-should-retry: false y envía una Idempotency-Key en todo lo que cueste dinero.
import random import time import uuid import requests def post_with_retry(url, headers, body, attempts=5): headers = {**headers, "Idempotency-Key": str(uuid.uuid4())} # same key on every attempt for attempt in range(attempts): r = requests.post(url, headers=headers, json=body, timeout=120) if r.status_code < 400: return r.json() if r.headers.get("x-should-retry") == "false": r.raise_for_status() if r.status_code not in (429, 503) or attempt == attempts - 1: r.raise_for_status() wait = float(r.headers.get("Retry-After", 2 ** attempt)) time.sleep(wait + random.random()) # jitter
async function postWithRetry(url: string, body: unknown, attempts = 5) {
const headers = {
Authorization: `Bearer ${process.env.HYPEROUTER_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(), // same key on every attempt
};
for (let attempt = 0; ; attempt++) {
const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
if (res.ok) return res.json();
const retryable = [429, 503].includes(res.status) && res.headers.get("x-should-retry") !== "false";
if (!retryable || attempt === attempts - 1) throw new Error(`HTTP ${res.status}`);
const wait = Number(res.headers.get("Retry-After") ?? 2 ** attempt);
await new Promise((r) => setTimeout(r, (wait + Math.random()) * 1000));
}
}
En una solicitud de chat, el reintento recibe 409 idempotency_key_replayed si el primer intento sí se ejecutó. Esa es la señal para leer el registro con GET /v1/generations/{id} y parar.
Los SDK de OpenAI ya reintentan dos veces un 408, 409, 429 o 5xx y respetan x-should-retry: false, así que quizá no necesites ningún bucle.
Qué sigue
- Errores enumera cada código con su estado.
- Cita el
idde la solicitud cuando abras un ticket: Cada solicitud tiene un ID que puedes citar.