500 et 502 indiquent une défaillance, pas une limite. Cela en fait la seule classe d’erreurs de cette famille qui mérite une nouvelle tentative presque immédiate — contrairement au 429, qui correspond à votre propre limite de débit, et au 529, qui indique que le fournisseur est saturé. Réessayer le mauvais code parmi les trois transforme un petit incident en votre propre incident.
L’erreur
// Straight from the model provider (HTTP 500)
{
"type": "error",
"error": { "type": "api_error", "message": "Internal server error" }
}
// From a gateway or proxy in between (HTTP 502)
{
"error": {
"message": "Failed to reach upstream provider",
"type": "upstream_error",
"code": "upstream_error",
"param": null
}
}Causes et solutions en bref
| Cause | Solution |
|---|---|
| Défaillance transitoire côté fournisseur | Réessayez avec un backoff exponentiel et une temporisation aléatoire, limité à ~5 tentatives. |
| Connexion acceptée, puis aucune réponse | Un blocage, pas une erreur. Limitez séparément le délai jusqu’au premier octet et la durée totale. |
| Un intermédiaire renvoie son propre 502 | Cela n’a rien à voir avec le modèle. Vérifiez si le corps de la réponse a le format du fournisseur ou celui d’un proxy. |
| Réessayer aveuglément pendant un véritable incident | Limitez le nombre de tentatives et appliquez un backoff — sinon vos nouvelles tentatives feront partie de la panne. |
Distinguer 500 de 529 et 429 avant de choisir une solution
429 est une limite de débit que vous dépassez — ralentissez. 529 signifie que le fournisseur est à capacité maximale — appliquez un backoff beaucoup plus important et plus long. 500/502 est une défaillance, généralement brève et souvent propre à une requête. Seul le troisième cas mérite une nouvelle tentative rapide, et traiter les trois de la même manière explique pourquoi les boucles de nouvelles tentatives aggravent les incidents.
Réessayer les 5xx, jamais les 4xx
Backoff exponentiel avec temporisation aléatoire, cinq tentatives maximum. Le même utilitaire fonctionne pour tous les fournisseurs — un 400 ou un 422 échouera de la même manière à la tentative suivante, donc le réessayer ne fait qu’ajouter de la latence avant la même erreur.
import time, random
from openai import OpenAI, APIStatusError
client = OpenAI(base_url="https://api.kunavo.com/v1", api_key="sk-kn-...")
def with_backoff(fn, max_retries=5):
for attempt in range(max_retries):
try:
return fn()
except APIStatusError as e:
if e.status_code not in (429, 500, 529):
raise # don't retry auth/validation errors
retry_after = e.response.headers.get("retry-after")
delay = float(retry_after) if retry_after else min(2 ** attempt, 30)
time.sleep(delay + random.uniform(0, 0.5)) # jitter avoids herds
raise RuntimeError("retries exhausted")
resp = with_backoff(lambda: client.chat.completions.create(
model="claude-sonnet-5",
messages=[{"role": "user", "content": "ping"}],
max_tokens=32,
))
print(resp.choices[0].message.content)Encadrez séparément le délai avant le premier octet et la durée totale
Un délai unique pour l’ensemble de la requête ne permet pas de distinguer une génération longue d’une connexion inactive. Définissez un délai court pour le premier octet et un délai généreux pour le reste ; un blocage échoue alors rapidement tandis qu’une réponse réellement lente est laissée se poursuivre.
Enregistrer le statut et la latence de chaque tentative
Sans enregistrements par tentative, un incident fournisseur et votre propre délai d’expiration semblent identiques a posteriori. Le code de statut, la latence et le numéro de tentative suffisent à les distinguer le lendemain matin.
Si vous appelez via Kunavo
En septembre 2026, tous les modèles Claude sur Kunavo sont servis via un seul canal amont ; un 5xx provenant de ce canal n’est donc pas réessayé à l’intérieur de la requête : il vous parvient sous forme de 502 avec le message « Upstream provider error » (typé api_error sur /v1/messages), et la requête est enregistrée avec un coût nul. La nouvelle tentative intégrée à la requête par Kunavo ne s’exécute que pour un modèle auquel un second canal est configuré : un délai d’expiration, un 5xx, un 429 ou le rejet de la propre clé amont de Kunavo est alors réessayé sur ce canal avant de vous parvenir, sur /v1/messages, /v1/responses et les modèles Claude sur /v1/chat/completions. Un flux est retenu jusqu’à l’arrivée de son premier contenu ; une erreur dans un flux qui n’a pas encore commencé est donc également réessayée. Une fois le contenu en cours d’envoi, une défaillance au milieu du flux doit être gérée par vos soins. Dans tous les cas, conservez la politique de nouvelle tentative de cette page côté client. Le routage derrière ce comportement est décrit dans notre guide de passerelle IA.
Questions fréquentes
Une requête qui renvoie 500 est-elle facturée ?
Sur Kunavo, non — les requêtes échouées sont enregistrées avec un coût nul. La facturation directe par un fournisseur varie, mais un 5xx n’est généralement pas facturé.
Une nouvelle tentative après un 500 peut-elle produire deux complétions ?
Oui. Une requête peut échouer après que le modèle a déjà généré du contenu. Si le traitement a des effets de bord, rendez-le idempotent à votre niveau avant d’ajouter des nouvelles tentatives.
Quelle est la différence en une ligne entre 500, 502 et 529 ?
500 signifie que le fournisseur rencontre une défaillance, 502 qu’un élément situé devant lui ne parvient pas à l’atteindre, et 529 que le fournisseur est à capacité maximale — réessayez rapidement pour les deux premiers et beaucoup plus tard pour le troisième.
Guides associés
- API Claude : 529 overloaded_error — ce que cela signifie et comment tenir le coup
- Claude API 429 rate_limit_error — causes et solution durable
La sémantique détaillée des erreurs est disponible dans référence des erreurs ; obtenir une clé prend une minute via inscription et la guide d’authentification.