L'API Qwen se consomme de deux manières courantes : l'interface native DashScope d'Alibaba Cloud Bailian, et l'interface compatible OpenAI. Les structures d'erreur diffèrent en partie, mais l'ordre de diagnostic reste le même : lire d'abord le code de statut HTTP, puis le code et le message du corps de réponse, retrouver le request_id, reproduire avec une requête minimale, et seulement ensuite modifier les paramètres ou changer de modèle.

Cet article détaille 401, 404, 429, 400, 5xx et timeouts, avec une table des codes d'erreur, les champs de journalisation, un exemple de reprise et une liste à préparer avant de contacter le support. Les modèles, quotas et tarifs font foi dans la documentation officielle et sur la page Tarifs des modèles.

Remarque : Qwen, Tongyi Qianwen, Alibaba Cloud, Bailian et DashScope sont des marques du groupe Alibaba et de leurs détenteurs respectifs. Cet article est purement technique et n'implique aucune affiliation, agence ou coopération avec ces sociétés. Les codes d'erreur, règles de limitation et comportements d'interface peuvent évoluer selon les versions ; la documentation officielle et la réponse réelle font foi.

1. Distinguer d'abord le mode d'interface et la structure d'erreur

L'interface native DashScope renvoie généralement code, message et request_id à la racine de la réponse ; l'interface compatible OpenAI reprend le style OpenAI, avec un corps du type {"error": {"message": "...", "type": "...", "code": "..."}}. En mode compatible, le request_id peut apparaître dans les en-têtes ou dans le corps ; le nom du champ dépend de la réponse réelle.

Côté ingénierie, ne parsez pas une seule structure. Enregistrez d'abord le corps complet tel quel dans les journaux, puis lisez successivement error.code et le code de premier niveau. Ainsi, un changement de mode d'interface n'oblige pas à réécrire le traitement des erreurs.

2. 401 : échec d'authentification, vérifier d'abord la région

Un 401 signifie que l'identité n'a pas été validée ; cela n'a généralement rien à voir avec les capacités du modèle ou le solde. Trois erreurs fréquentes chez Bailian :

  • InvalidApiKey ou invalid_api_key : clé erronée, copie incomplète, ou URL de base incohérente avec la région de la clé.
  • invalid access token or token expired : token expiré, ou adresse réservée à une offre utilisée avec une clé ordinaire.
  • Refus d'autorisation : WorkspaceId invalide, ou compte absent de cet espace de travail.

Les clés API Qwen sont liées à une région : celles de Pékin et de Singapour ne se mélangent pas. C'est l'erreur la plus facile à manquer : le code ne change pas, seule l'URL de base change, et le 401 se reproduit systématiquement.

Procédez dans l'ordre :

  1. Vérifiez que l'en-tête est Authorization: Bearer <clé>, avec un espace après les deux-points.
  2. Affichez le préfixe de la variable d'environnement pour écarter une valeur vide, obsolète ou un saut de ligne.
  3. Vérifiez la cohérence entre l'URL de base et la région de la clé.
  4. Confirmez que le type de clé correspond à l'interface : paiement à l'usage, offre Coding et offre Token n'utilisent pas la même adresse.
  5. Testez une nouvelle clé sur une requête minimale pour distinguer un problème de clé d'un problème de proxy ou de passerelle.

3. 404 et 400 : nom du modèle, activation et contexte

Un 404 n'est le plus souvent pas une panne du service, mais un problème de nom ou de disponibilité du modèle. Face à ModelNotFound ou model_not_found, vérifiez trois choses : le nom est-il mal orthographié, le modèle est-il activé, le modèle est-il disponible dans la région actuelle. model_not_supported indique que le modèle ne prend pas en charge le mode compatible OpenAI : changez d'interface ou de modèle.

Les causes de 400 sont plus diverses. InvalidParameter signale un paramètre hors limites, par exemple temperature ou top_p hors plage ; InvalidParameter.NotSupportEnableThinking indique que le modèle ne prend pas en charge le paramètre de mode réflexion. Le dépassement de contexte renvoie souvent Range of input length should be [1, xxx], avec le code sous-jacent InternalError.Algo.InvalidParameter, ou bien la longueur totale des messages dépasse la limite du modèle. La solution consiste à tronquer l'historique, à résumer par blocs ou à passer à un modèle à contexte long, pas à réessayer en boucle.

4. 429 : distinguer quatre limitations et deux types de quota

Le 429 est l'erreur la plus souvent mal traitée. Chez Bailian, il couvre au moins les cas suivants ; le tableau inclut aussi les erreurs d'impayé et de service non activé qui se confondent facilement avec une limitation :

HTTP Code d'erreur Signification Reprise pertinente
429 Throttling.RateQuota, LimitRequests Requêtes par minute (RPM) dépassées Oui, après backoff
429 Throttling.AllocationQuota, insufficient_quota Tokens par minute (TPM) dépassés Oui, backoff et réduction de l'entrée
429 Throttling.BurstRate Protection déclenchée par un pic de trafic Oui, lisser le débit
429 Throttling.Concurrency Trop de requêtes simultanées Oui, réduire la concurrence
429 AllocationQuota.FreeTierOnly Quota gratuit épuisé avec l'option « gratuit uniquement » activée Non, recharger ou désactiver l'option
429 BudgetLimitExceeded Budget du compte épuisé Non, ajuster le budget
400 Arrearage Compte impayé ou statut anormal Non, rétablir d'abord le compte
403 AccessDenied.Unpurchased Service non activé Non, activer d'abord

La limitation est calculée au niveau du compte principal Alibaba Cloud : les appels des sous-comptes RAM, des espaces de travail et de plusieurs clés sont cumulés. « Une clé par service » ne contourne donc pas le quota total ; cela évite seulement que les services se gênent entre eux. La limitation se rétablit généralement à l'échelle de la minute ; n'effectuez pas de reprises à haute fréquence pendant l'attente.

5. Timeouts et 5xx : localiser en trois segments

Un timeout se lit en trois segments : le timeout de connexion indique généralement un DNS, une sortie ou un proxy injoignable ; un premier token lent vient souvent d'une file amont ou d'une entrée trop longue ; un timeout de lecture peut venir d'une sortie trop longue ou d'une inférence prolongée. Les traitements diffèrent : augmenter uniquement le timeout global ne suffit pas.

Chez Bailian, RequestTimeOut signale un dépassement du délai de requête, la documentation officielle mentionnant une limite de 300 secondes ; GatewayTimeout.InputDownload concerne le téléchargement du fichier d'entrée. L'interface compatible OpenAI peut aussi renvoyer 503 lorsque le moteur est surchargé. En cas d'interruption du flux, il peut n'y avoir aucun code d'erreur : notez le contenu déjà reçu, le dernier segment et la raison de fin, puis distinguez gigue réseau, coupure du proxy et timeout amont.

6. request_id et journaux : les preuves du diagnostic

La documentation officielle indique que le request_id accompagne la réponse, dans l'en-tête ou dans le corps. Côté ingénierie, une double journalisation est recommandée : un trace_id généré par le client et conservé sur toutes les tentatives, plus la sauvegarde brute de l'identifiant de requête des en-têtes et du request_id du corps. À défaut, recherchez-le dans les journaux de supervision des modèles de la console, à condition que la journalisation d'inférence soit activée.

Le journal doit contenir au minimum : heure, trace_id, URL de base, région, nom du modèle, code HTTP, code d'erreur, message d'erreur, request_id, durée, nombre de tentatives et caractère streaming. Pour la clé, n'enregistrez que les premiers caractères ou un hachage ; le texte utilisateur et la réponse complète ne doivent pas être écrits en entier sur disque. Pour contacter le support, une entrée contenant ces champs est bien plus utile qu'un « il y a parfois une erreur ».

7. Reprises et backoff : exemple de code

Le code ci-dessous désactive les reprises automatiques du SDK, ne réessaie que les 429 et 5xx récupérables, et imprime ensemble code de statut, code d'erreur et request_id. Les impayés, l'épuisement du quota gratuit et le dépassement de budget sont exclus des reprises.

import os
import random
import time
import uuid

import httpx
from openai import OpenAI, APIConnectionError, APIStatusError, APITimeoutError

client = OpenAI(
    api_key=os.environ["DASHSCOPE_API_KEY"],
    base_url=os.environ.get(
        "DASHSCOPE_BASE_URL",
        "https://dashscope.aliyuncs.com/compatible-mode/v1",
    ),
    timeout=httpx.Timeout(connect=5.0, read=180.0, write=30.0, pool=10.0),
    max_retries=0,  # désactive les reprises du SDK, gérées ci-dessous
)

RETRYABLE_429 = {
    "Throttling",
    "Throttling.RateQuota",
    "Throttling.AllocationQuota",
    "Throttling.BurstRate",
    "Throttling.Concurrency",
    "LimitRequests",
    "limit_requests",
    "ResourceExhausted",
}

def unpack_error(exc: APIStatusError):
    body = {}
    try:
        body = exc.response.json()
    except Exception:
        pass
    err = body.get("error", body) if isinstance(body, dict) else {}
    code = err.get("code") if isinstance(err, dict) else None
    request_id = None
    if isinstance(body, dict):
        request_id = body.get("request_id")
    request_id = (
        request_id
        or exc.response.headers.get("x-request-id")
        or exc.response.headers.get("x-dashscope-request-id")
    )
    return code, request_id, exc.response.text[:500]

def ask(prompt: str, model: str, max_attempts: int = 4) -> str:
    trace_id = uuid.uuid4().hex[:12]
    for attempt in range(1, max_attempts + 1):
        try:
            resp = client.chat.completions.create(
                model=model,
                messages=[{"role": "user", "content": prompt}],
            )
            return resp.choices[0].message.content
        except APIStatusError as exc:
            code, request_id, body = unpack_error(exc)
            print(
                f"trace={trace_id} attempt={attempt} "
                f"http={exc.status_code} code={code} "
                f"request_id={request_id} body={body}"
            )
            retryable = exc.status_code >= 500 or (
                exc.status_code == 429 and code in RETRYABLE_429
            )
            if not retryable or attempt == max_attempts:
                raise
        except (APITimeoutError, APIConnectionError) as exc:
            print(f"trace={trace_id} attempt={attempt} err={type(exc).__name__}")
            if attempt == max_attempts:
                raise
        wait = min(2 ** (attempt - 1), 30) + random.uniform(0, 1)
        time.sleep(wait)
    raise RuntimeError("Nombre de tentatives épuisé")

Trois règles complémentaires : respectez en priorité le Retry-After renvoyé par le serveur ; contrôlez globalement le budget de reprises pour éviter que plusieurs services n'amplifient le trafic ; pour les requêtes à effet de bord, vérifiez d'abord si elles ont été exécutées avant de renvoyer.

8. Gouvernance de la concurrence : plus efficace que d'augmenter les reprises

Les problèmes de limitation ne se règlent généralement pas par les reprises, mais par la gouvernance de l'entrée :

  • Découpez les clés par activité et fixez un plafond de concurrence distinct, pour qu'une tâche batch ne fasse pas tomber le service en ligne.
  • Fragmentez les tâches batch et décalez les horaires pour éviter le pic de l'heure pile.
  • Lissez avec une file : les tâches échouées vont dans une file différée au lieu de tourner en boucle.
  • Surveillez la part de 429 et la latence p95 ; en cas de hausse soudaine, réduisez d'abord la concurrence.
  • Pour les tâches hors ligne, privilégiez l'interface Batch afin d'éviter la limitation en temps réel.
  • Prévoyez un modèle ou un point d'entrée de secours, en vérifiant la compatibilité des paramètres avant bascule.

Les seuils de limitation dépendent du modèle et du compte ; un rechargement n'augmente pas automatiquement le RPM ou le TPM. Pour un quota supérieur, passez par une demande commerciale, sans recopier les chiffres d'autrui.

9. Liste à préparer avant de contacter le support

  1. Heure et fuseau de l'incident, caractère soudain ou progressif.
  2. URL de base, région, chemin d'interface, nom du modèle et méthode d'appel.
  3. Code HTTP, code d'erreur et message d'erreur complet.
  4. request_id ; à défaut, votre trace_id.
  5. Une requête curl minimale reproductible, clé masquée.
  6. Streaming ou non, contexte long ou non, configuration récemment modifiée ou non.
  7. Périmètre d'impact : une clé, un espace de travail ou tous les services.

10. Questions fréquentes

Un 429 est-il toujours une limitation de débit ?

Non. Un 429 peut aussi signaler un quota gratuit épuisé ou un budget dépassé ; un impayé peut renvoyer un 400 Arrearage, et un service non activé un 403. Lisez le code d'erreur avant de choisir entre backoff, recharge et modification de configuration.

Que faire si un 401 persiste avec une nouvelle clé ?

Vérifiez surtout la région et le type de clé. Les clés Qwen sont liées à une région : une clé de Pékin avec une adresse de Singapour renvoie 401 ; une adresse réservée à une offre avec une clé ordinaire échoue aussi. Contrôlez ensuite l'en-tête, la variable d'environnement et le proxy inverse, qui peut supprimer l'authentification.

Comment traiter un dépassement de contexte ?

Tronquez d'abord l'historique, retirez les pièces jointes inutiles et les passages répétés ; résumez ou indexez ensuite les documents longs ; si cela ne suffit pas, passez à un modèle à contexte long. N'essayez pas de résoudre un dépassement d'entrée en augmentant max_tokens.

Faut-il réessayer après un timeout ?

Seulement un nombre limité de fois pour les échecs de connexion et les timeouts de lecture, avec backoff exponentiel et plafond. Pour les opérations à effet de bord, vérifiez d'abord si elles ont été exécutées afin d'éviter une double commande ou écriture.

Où trouver le request_id ?

Regardez d'abord les en-têtes et le corps de la réponse, le nom du champ dépendant de l'interface réelle ; s'il n'est pas journalisé, cherchez dans les journaux de supervision des modèles de la console, à condition que la journalisation d'inférence soit activée. Pour le support, fournissez à la fois le trace_id et une requête de reproduction minimale.

Pour aller plus loin

Créez d'abord une clé de test sur ZSQH AI Gateway, entraînez-vous une fois sur 401, 404, 429, dépassement de contexte et timeout, puis branchez la supervision de production. Les modèles disponibles et la facturation figurent sur la page Tarifs des modèles.

Articles liés :