Des erreurs sur lesquelles agir

· Hyperouter · 5 min de lecture

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"
  }
}
ChampSignification
messageUne phrase qui dit ce qui ne va pas. Ne l’analysez pas.
typeLa classe d’erreur.
codeUn identifiant stable de la cause. Fiez-vous à ce champ.
paramLe 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

StatutSignificationQue faire
400La requête est invalide. code désigne la cause et param le champ.Corrigez la requête. Ne la réessayez pas telle quelle.
401La clé API est absente ou invalide.Vérifiez la clé.
402insufficient_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é.
403Le compte est suspendu, ou une fonctionnalité ou un modèle n’est pas activé pour lui.Ouvrez un ticket de support.
404Cet id n’existe pas, l’id appartient à un autre compte, ou une vidéo a dépassé son expires_at.Ne réessayez pas.
409L’objet n’est pas dans un état qui autorise l’appel, ou conflit d’Idempotency-Key.Voir réessayer en toute sécurité.
429Tous 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, 501Hyperouter a échoué, ou l’endpoint n’est pas implémenté. Non facturé.Réessayez un 500 avec prudence, comme ci-dessous.
503Un fournisseur a échoué ou n’a pas répondu à temps.Réessayez, comme ci-dessous.

Trois codes que vous rencontrerez

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 :

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

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