Des erreurs sur lesquelles agir
Chaque erreur d’Hyperouter utilise l’objet d’erreur d’OpenAI et un statut HTTP correspondant. Le code qui gère déjà les erreurs d’OpenAI gère la plupart de celles-ci. Ce guide couvre ce qui mérite une action et ce qui n’en mérite pas, et se termine par une boucle de nouvelles tentatives.
L’objet d’erreur
{
"error": {
"message": "n must be an integer from 1 to 128",
"type": "invalid_request_error",
"code": "invalid_body",
"param": "n"
}
}
| Champ | Signification |
|---|---|
message | Une phrase qui dit ce qui ne va pas. Ne l’analysez pas. |
type | La classe d’erreur. |
code | Un identifiant stable de la cause. Fiez-vous à ce champ. |
param | Le champ de la requête en cause, ou null. |
Certaines erreurs ajoutent generation_id : l’id d’une tâche encore en cours ou déjà exécutée. Interrogez-le avec GET /v1/generations/{id}.
Les statuts à traiter
| Statut | Signification | Que faire |
|---|---|---|
400 | La requête est invalide. code désigne la cause et param le champ. | Corrigez la requête. Ne la réessayez pas telle quelle. |
401 | La clé API est absente ou invalide. | Vérifiez la clé. |
402 | insufficient_credits : votre solde, ou la limite de la clé, ne peut pas couvrir le coût maximal de la requête. | Rechargez, ou relevez la limite de la clé. |
403 | Le compte est suspendu, ou une fonctionnalité ou un modèle n’est pas activé pour lui. | Ouvrez un ticket de support. |
404 | Cet id n’existe pas, l’id appartient à un autre compte, ou une vidéo a dépassé son expires_at. | Ne réessayez pas. |
409 | L’objet n’est pas dans un état qui autorise l’appel, ou conflit d’Idempotency-Key. | Voir réessayer en toute sécurité. |
429 | Tous les fournisseurs sont saturés, ou votre compte dépasse ses limites de débit. | Attendez le délai de Retry-After, puis réessayez. |
500, 501 | Hyperouter a échoué, ou l’endpoint n’est pas implémenté. Non facturé. | Réessayez un 500 avec prudence, comme ci-dessous. |
503 | Un fournisseur a échoué ou n’a pas répondu à temps. | Réessayez, comme ci-dessous. |
Trois codes que vous rencontrerez
insufficient_credits(402). Sur le chat, le message indique combien de tokens vous pouvez vous permettre. Baissermax_tokensbaisse le coût maximal de la requête. Une recharge est une demande manuelle dans le tableau de bord ; GET /v1/credits vous permet de la voir venir.model_not_enabled(403). Le modèle exige un accès accordé à votre compte. Ouvrez un ticket de support pour le demander. Rien n’est bloqué ni envoyé au fournisseur.rate_limited(429). Votre compte dépasse ses requêtes par minute ou ses requêtes simultanées. Rien n’est bloqué ni transmis. La réponse porte un en-têteRetry-Afteren secondes, et la section limites de débit liste les paliers.
La même famille inclut venue_busy (429) : tous les fournisseurs d’un modèle de chat ont dépassé leur budget de débit.
Pourquoi 503, et non 502 ou 504
Hyperouter ne répond jamais 502 ni 504. Ils vous parviendraient sous forme de page brute de notre réseau en périphérie, sans le corps d’erreur, et vous ne pourriez pas lire code.
Là où une passerelle les répondrait, vous recevez 503 avec l’objet d’erreur habituel, et le statut de la passerelle dans l’en-tête de réponse X-Upstream-Status : 502 lorsqu’un fournisseur a échoué, 504 lorsqu’il a dépassé le délai. Le code dit de quel type d’échec il s’agit : all_venues_failed, upstream_error ou timeout.
HTTP/2 503
x-upstream-status: 504
Lisez X-Upstream-Status si vous voulez distinguer un échec d’un délai dépassé. Pour la plupart des codes, 503 et code suffisent.
Quand ne pas réessayer
Réessayer n’est pas toujours sûr. Une nouvelle tentative peut démarrer une seconde tâche ou un second débit. Hyperouter marque ces réponses avec x-should-retry: false :
- le
503timeoutd’une image synchrone. La tâche continue et est facturée si elle réussit. Interrogez plutôterror.generation_id; - un
500après la création d’une tâche ; 409idempotency_key_reusedetidempotency_key_replayed.
Sur le chat, un fournisseur qui a accepté une requête est peut-être en train de l’exécuter. S’il cesse ensuite de répondre, la requête n’est pas envoyée à un autre fournisseur : la réponse est 503 avec le code timeout ou upstream_error, et elle est facturée sur son montant bloqué. Retrouvez-la avec GET /v1/generations/{id} avant de décider de la renvoyer.
Une boucle de nouvelles tentatives avec backoff
Réessayez 429 et 503, respectez Retry-After, abandonnez sur x-should-retry: false, et envoyez une Idempotency-Key sur tout ce qui coûte de l’argent.
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));
}
}
Sur une requête de chat, la nouvelle tentative reçoit 409 idempotency_key_replayed si la première tentative a bien été exécutée. C’est le signal pour lire l’enregistrement avec GET /v1/generations/{id} et s’arrêter.
Les OpenAI SDK réessaient déjà deux fois une réponse 408, 409, 429 ou 5xx et respectent x-should-retry: false : vous n’avez peut-être besoin d’aucune boucle.
Et ensuite
- Erreurs liste chaque code avec son statut.
- Citez l’
idde la requête quand vous ouvrez un ticket : Chaque requête a un id que vous pouvez citer.