FR ▾
Obtenir votre clé API

Guide de dépannage des codes d'erreur API sans censure

Les erreurs ne sont pas effrayantes, le problème est de ne pas savoir s'il faut réessayer ou modifier le code. Ce guide décompose chaque code d'état : conditions de déclenchement, critères de décision et correctifs. Le corps d'erreur est toujours un JSON avec un objet error contenant code et message ; la première étape est donc de lire le corps, pas seulement le code d'état. Nous fournissons du code de réessai avec rétrogradation exponentielle, du code de limitation de débit côté client et une liste de vérification.

Mis à jour le

Points clés

  • Seuls les codes 429 et 503 méritent un réessai automatique ; réessayer les autres gaspille vos requêtes.
  • 402 no_credit signifie solde épuisé ou essai expiré ; 403 content_blocked signifie contenu bloqué. Ce ne sont pas des problèmes réseau.
  • Les réessais doivent inclure une rétrogradation exponentielle avec un jitter aléatoire et un nombre maximal de tentatives.
  • Chaque clé API est limitée à 300 requêtes par minute ; les tâches par lots doivent limiter le débit côté client.

Format du corps d'erreur et ordre de lecture

Toutes les réponses d'échec ont la même structure :

{"error":{"code":"...","message":"..."}}

L'ordre de lecture est fixe :

  1. Le code d'état HTTP détermine la catégorie ;
  2. error.code détermine la cause spécifique et sert de condition dans le code ;
  3. error.message est destiné à l'affichage et à la journalisation, pas à la correspondance de chaînes.

Distinguez clairement deux cas : ceux que des tentatives peuvent résoudre (429, 503, timeouts réseau) et ceux qui nécessitent une modification (les autres). Les mélanger est la cause la plus fréquente des incidents en production, par exemple en tentant à l'infini un 402, ce qui génère des dizaines de requêtes invalides par seconde.

Dans les logs, enregistrez toujours quatre champs : l'heure, le code de statut, error.code et l'estimation des prompt_tokens de la requête. En cas de problème, vous voyez immédiatement si une catégorie d'erreurs augmente ou si les échecs sont globaux. Ajoutez une règle d'alerte : un 402 déclenche une notification immédiate car il signifie que le service est indisponible pour l'utilisateur ; pour un 429, observez le taux : une occurrence isolée n'est pas un problème, mais une persistance indique un problème de concurrence.

Tableau des codes d'état

Code d'étaterror.codeSignificationRéessayer ?
400—Requête invalide, ex. prompt + max_tokens > 100kNon
401—Clé invalide ou manquanteNon
402no_creditSolde épuisé ou essai expiréNon
403content_blockedContenu bloquéNon
404—Endpoint inexistantNon
429—Limite de débit atteinteOui, backoff
503upstream_busyService temporairement occupéOui, après quelques secondes

Le tiret « — » dans le tableau indique qu'il n'y a pas de code string fixe à gérer ; branchez simplement sur le code d'état.

4xx : modifiez la requête, ne réessayez pas

400 Requête invalide

  • Cause 1 : Erreur de format JSON, souvent due à des guillemets non échappés dans une chaîne saisie manuellement.
  • Cause 2 : prompt + max_tokens > 100,000. Les longues conversations sont les plus touchées.
  • Cause 3 : Corps de requête > 8 MB.
  • Correctif : sérialisez avec une bibliothèque JSON ; estimez les tokens avant l'envoi et coupez l'historique ou réduisez max_tokens si nécessaire ; voir Long contexte en pratique.

401 Problème de clé

  • En-tête manquant ou préfixe Bearer absent.
  • La clé a été régénérée ; l'ancienne devient immédiatement invalide, mais un serveur l'utilise encore.
  • La variable d'environnement n'est pas injectée dans le conteneur ou la tâche planifiée.

402 no_credit

Solde épuisé ou essai gratuit de 7 jours expiré. Allez sur la page de compte pour recharger votre crédit prépayé et rétablir le service. Nous vous recommandons de surveiller votre solde avec votre propre service de monitoring, plutôt que d'attendre que les utilisateurs signalent une erreur.

403 content_blocked

Contenu bloqué. Le contenu adulte légitime, la fiction et les sujets controversés ne sont pas refusés, mais le contenu sexuel impliquant des mineurs est systématiquement bloqué, qu'il s'agisse de romans ou de jeux de rôle. En cas d'erreur 403, vérifiez l'entrée et l'historique pour détecter ce type de contenu ; il est plus efficace de corriger cela que de réessayer avec une formulation différente.

L'endpoint n'existe pas (404)

Seuls deux endpoints sont disponibles : POST /v1/chat/completions et GET /v1/models. Un chemin manquant /v1, un slash supplémentaire, une faute de frappe ou l'appel d'interfaces non prises en charge comme embeddings ou images provoqueront une erreur 404.

Un autre cas 400 facile à mal interpréter : le nombre de tokens augmente linéairement avec le nombre de tours dans une longue conversation. Les tests diurnes fonctionnent bien, mais après quelques dizaines de tours, des erreurs 400 apparaissent soudainement. Ce n'est pas une instabilité de l'API, mais la fenêtre de contexte est pleine. La solution consiste à limiter l'historique : supprimez les tours les plus anciens lorsque le seuil est dépassé, ou compressez les anciens contenus en résumés. Estimez la taille avant d'envoyer la requête plutôt que d'attendre l'erreur.

Une astuce pour diagnostiquer une erreur 401 consiste à imprimer les quatre premiers et les quatre derniers caractères de la clé dans les logs, sans afficher le contenu complet, puis à les comparer avec ceux affichés sur la page du compte. Cela permet de confirmer si le processus lit bien la clé attendue. Dans les environnements conteneurisés ou les tâches planifiées, l'absence de variables d'environnement ou la lecture d'une ancienne valeur sont les causes les plus fréquentes.

429 et 503 : les deux cas où il faut réessayer

Limite de débit 429

Chaque clé est limitée à 300 requêtes par minute. Les tâches par lots, le partage d'une même clé entre plusieurs instances ou une tempête de réessais peuvent déclencher cette limite. La correction s'effectue en deux étapes : limiter le débit côté client (voir le code ci-dessous), puis réessayer avec une stratégie d'atténuation sur les erreurs 429.

503 upstream_busy

Le service est temporairement occupé. Réessayez après quelques secondes. Évitez d'envoyer des requêtes en rafale ou de réessayer dix fois en une seconde, cela aggraverait la situation.

Délai d'attente réseau (timeout)

La génération de longs textes prend du temps ; ne définissez pas un timeout trop court, par exemple 120 secondes. Attention lors du réessai après un timeout : la requête précédente peut déjà avoir été exécutée côté serveur, ce qui entraînerait une consommation double de crédits. Pour les requêtes de génération, limitez le nombre de réessais et privilégiez le streaming pour réduire le temps d'attente par appel.

import os
import random
import time
import requests

URL = "https://api.wushenchaapi.com/v1/chat/completions"
HEADERS = {
    "Authorization": "Bearer " + os.environ["API_KEY"],
    "Content-Type": "application/json",
}
RETRYABLE = {429, 503}          # 只重试这两类
FATAL = {400, 401, 402, 403, 404}

class ApiError(Exception):
    def __init__(self, status, code, message):
        super().__init__(f"{status} {code}: {message}")
        self.status, self.code = status, code

def call(payload, max_retries=5, base=1.0, cap=30.0):
    for attempt in range(max_retries + 1):
        try:
            r = requests.post(URL, headers=HEADERS, json=payload, timeout=120)
        except (requests.ConnectionError, requests.Timeout):
            r = None                      # 网络层失败,按可重试处理
        if r is not None and r.ok:
            return r.json()
        if r is not None:
            try:
                err = r.json().get("error", {})
            except ValueError:
                err = {}
            if r.status_code in FATAL or r.status_code not in RETRYABLE:
                raise ApiError(r.status_code, err.get("code"), err.get("message"))
        if attempt == max_retries:
            raise ApiError(r.status_code if r is not None else 0, "retry_exhausted", "重试次数用尽")
        delay = min(cap, base * (2 ** attempt)) * random.uniform(0.5, 1.0)
        time.sleep(delay)

if __name__ == "__main__":
    out = call({"model": "uncensored", "max_tokens": 100,
                "messages": [{"role": "user", "content": "回复一个字:好"}]})
    print(out["choices"][0]["message"]["content"])

Point clé : la formule d'atténation est min(cap, base × 2^n) × coefficient aléatoire. Le jitter aléatoire évite que plusieurs clients ne réessaient simultanément. Les codes d'état de la liste FATAL ne font l'objet d'aucun réessai.

Limitation du débit côté client et requêtes de diagnostic

Il vaut mieux limiter le débit en amont plutôt que d'attendre une erreur 429. L'utilitaire suivant garantit que le nombre de requêtes reste inférieur à la valeur définie par minute, avec une sécurité multithread :

import threading
import time

class RateGate:
    """简单的客户端限速:保证一分钟内请求数不超过 limit。"""
    def __init__(self, limit=240):          # 留出余量,低于 300/分钟
        self.limit, self.stamps, self.lock = limit, [], threading.Lock()

    def wait(self):
        while True:
            with self.lock:
                now = time.time()
                self.stamps = [t for t in self.stamps if now - t < 60]
                if len(self.stamps) < self.limit:
                    self.stamps.append(now)
                    return
                sleep_for = 60 - (now - self.stamps[0])
            time.sleep(max(sleep_for, 0.05))

Pour le diagnostic, la méthode la plus propre consiste à s'affranchir du code métier et à envoyer une requête minimale avec curl. L'option -i permet d'afficher à la fois la ligne de statut et les en-têtes de réponse :

curl -i https://api.wushenchaapi.com/v1/chat/completions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"uncensored","max_tokens":20,"messages":[{"role":"user","content":"ping"}]}'

Si curl fonctionne mais que le code métier échoue, le problème vient de votre code ou de votre environnement (proxy, variables d'environnement, encodage). Si curl échoue également, vérifiez la clé, le solde et la connectivité réseau.

Pourquoi la limite de débit est fixée à 240 et non 300 : lors d'un déploiement multi-instances, chaque instance applique sa propre limite de débit, et la somme peut encore dépasser la limite globale ; les tentatives de retransmission consomment également du quota. Prévoir une marge de 20 % est une approche prudente. Si vous avez plusieurs instances, répartissez équitablement le quota total entre chaque instance ou utilisez un compteur partagé pour coordonner les requêtes simultanées.

Liste de vérification pour le débogage

  1. Lisez le error.code dans le corps de la réponse, ne vous fiez pas uniquement au code de statut HTTP.
  2. 401 : préfixe de la clé, variables d'environnement, vérifiez si la clé a été régénérée.
  3. 400 : le JSON est-il valide ? Le total prompt + max_tokens dépasse-t-il 100,000 tokens ? Le corps de la requête dépasse-t-il 8 Mo ?
  4. 402 : solde et validité de l'essai.
  5. 403 : l'entrée et l'historique contiennent-ils du contenu interdit ?
  6. 404 : le chemin correspond-il à /v1/chat/completions ou /v1/models ?
  7. 429 : plusieurs instances partagent-elles une même clé ? La limitation du débit côté client est-elle implémentée ?
  8. 503 : une stratégie de réessai avec atténuation est-elle en place ? L'intervalle est-il d'au moins quelques secondes ?
  9. Timeout : le timeout est-il suffisant ? Le passage au streaming est-il envisageable ?
  10. Si toutes les causes ci-dessus sont écartées, reproduisez le problème avec une requête minimale via curl.

Si vous débutez, consultez d'abord le guide d'intégration. Pour plus de paramètres, consultez la documentation.

Utilisation de la liste : en cas de problème, éliminez les causes de haut en bas, sans sauter d'étapes. La plupart des pannes « étranges » se situent dans les quatre premiers points.

Conseil supplémentaire : notez les conclusions de chaque diagnostic dans la documentation de votre équipe. La prochaine fois qu'une erreur similaire surviendra, vous pourrez l'identifier immédiatement.

Questions fréquentes

Combien de temps attendre avant de réessayer après une erreur 503 ?

Quelques secondes suffisent. Nous recommandons d'attendre une à deux secondes pour la première tentative, puis d'augmenter le délai de manière exponentielle en ajoutant un jitter aléatoire, tout en définissant un nombre maximal de réessais.

Pourquoi mes requêtes retournent-elles systématiquement une erreur 402 ?

Solde épuisé ou essai gratuit de 7 jours expiré. Rechargez votre crédit prépayé pour rétablir le service. Le solde n'expire pas.

L'erreur 403 content_blocked peut-elle être contournée en modifiant le texte ?

Ne tentez pas. Le contenu sexuel impliquant des mineurs est toujours bloqué, y compris dans les romans et le jeu de rôle. Le contenu adulte normal ne déclenche pas cette erreur.

La limite 429 s'applique-t-elle par compte ou par clé ?

La limite est de 300 requêtes par minute par clé. Chaque compte ne disposant que d'une seule clé, vous devez gérer la limite de débit conjointement si plusieurs services la partagent.

Remplissez simplement le formulaire pour obtenir votre clé

Créez un compte, copiez votre clé et modifiez l'URL de base. La configuration est aussi simple que cela.