AI Cert Prep
Saisissez un mot-clé pour rechercher dans la documentation.

Annexes · Claude

Raisons d'arrêt et erreurs

Chaque stop_reason et erreur HTTP avec cause, détection et code de traitement — la référence de fiabilité pour la boucle agentique.

Les items de fiabilité reposent sur deux énumérations : les valeurs de stop_reason sur lesquelles une boucle doit brancher, et les erreurs HTTP qu’un client doit classer en réessai-ou-correction. Cette page couvre chacune avec cause, détection et traitement.

La règle de fiabilité

Branchez sur stop_reason pour contrôler la boucle et sur le statut HTTP pour décider réessai vs correction. Ne parsez jamais la prose pour « done », n’utilisez jamais un plafond d’itérations comme arrêt principal, et ne réessayez jamais une erreur client 4xx.

stop_reason — chaque valeur

ValeurCauseDétectionTraitement
end_turnLe modèle a terminé naturellementstop_reason == "end_turn"Fini — renvoyez la réponse
tool_useLe modèle veut exécuter des outilsstop_reason == "tool_use"Exécuter tous les blocs tool_use, ajouter le(s) tool_result dans un message user, rappeler
max_tokensLa sortie a atteint max_tokensstop_reason == "max_tokens"Tronqué — continuer (« Continue. ») ou augmenter le plafond ; ne jamais traiter comme complet
stop_sequenceA atteint une chaîne d’arrêt configuréestop_reason == "stop_sequence" ; vérifiez stop_sequenceFini — la chaîne était le terminateur voulu
pause_turnLong tour d’outil côté serveur mis en pausestop_reason == "pause_turn"Renvoyer la conversation inchangée pour continuer
refusalLes systèmes de sécurité ont refuséstop_reason == "refusal"Repli explicite (reformuler, transfert humain, message sûr) ; ne réessayez pas aveuglément
python
def handle(r, messages):
sr = r.stop_reason
if sr == "tool_use":
messages.append({"role": "assistant", "content": r.content})
messages.append({"role": "user", "content": run_tools(r.content)})
return "continue"
if sr == "max_tokens":
messages.append({"role": "assistant", "content": r.content})
messages.append({"role": "user", "content": "Continue from where you stopped."})
return "continue"
if sr == "pause_turn":
return "resend" # re-send unchanged
if sr == "refusal":
return handle_refusal(r) # explicit fallback path
return "done" # end_turn / stop_sequence

max_tokens n’est pas un succès

Un arrêt max_tokens signifie que la réponse est coupée. La renvoyer comme finale est l’anti-pattern de silent-failure — particulièrement dangereux pour une sortie structurée où le JSON est désormais invalide.

Erreurs HTTP — chaque statut

HTTPTypeCauseRetry ?Traitement
400invalid_request_errorRequête malformée (p. ex. tool_choice forcé sur Fable 5.1, budget_tokens sur non-Haiku, mauvais schéma)NonCorriger la requête
401authentication_errorClé API manquante/invalideNonCorriger les identifiants
403permission_errorLa clé manque du droit d’accès (modèle/fonctionnalité)NonVérifier l’accès/le droit
404not_found_errorLe modèle/la ressource n’existe pas (p. ex. modèle retiré)NonCorriger l’ID / migrer
413request_too_largeLa charge utile dépasse les limitesNonRéduire l’entrée ; chunker ; Files API
429rate_limit_errorRPM/ITPM/OTPM dépassésOuiBackoff + jitter, respectez retry-after ; réduisez le débit proactivement
500api_errorErreur côté serveurOuiBackoff + jitter
529overloaded_errorCapacité saturéeOuiBackoff ; envisagez un repli vers un modèle plus récent ou équivalent
text
Retry? ── status in {429, 500, 502, 503, 529} ──► YES: exponential backoff + jitter, honour retry-after
└─ status in {400, 401, 403, 404, 413} ──► NO: fix the request/credentials/entitlement
python
import time, random
from anthropic import APIStatusError, RateLimitError, APIConnectionError
RETRYABLE = {429, 500, 502, 503, 529}
def call(fn, **params):
for attempt in range(6):
try:
return fn(**params)
except RateLimitError as e:
wait = float(e.response.headers.get("retry-after", 0)) or min(60, 2 ** attempt)
time.sleep(wait + random.uniform(0, 0.5))
except APIStatusError as e:
if e.status_code in RETRYABLE:
time.sleep(min(60, 2 ** attempt) + random.uniform(0, 0.5))
else:
raise # 4xx → fix, don't retry
except APIConnectionError:
time.sleep(min(60, 2 ** attempt) + random.uniform(0, 0.5))
raise RuntimeError("exhausted retries")

Erreurs de streaming

Un événement error peut arriver en cours de flux (communément overloaded_error). Traitez-le comme le statut HTTP : surcharge/timeout réessayable → backoff et redémarrez le flux ; requête malformée → corrigez.

text
event: error
data: {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}

Erreurs d’exécution d’outil (pas HTTP)

Un outil qui échoue n’est pas une erreur API — l’appel API a réussi. Renvoyez un tool_result structuré avec is_error: true :

json
{ "type": "tool_result", "tool_use_id": "toolu_01", "is_error": true,
"content": "{\"category\":\"not_found\",\"retryable\":false,\"message\":\"No order ORD-999\"}" }
CategorySignificationLe modèle devrait
not_foundRessource absenteLe dire à l’utilisateur, demander un ID valide
invalid_inputMauvais argumentsCorriger et réessayer
transientTemporaire (timeout)Réessayer une fois, puis signaler
forbiddenNon autoriséS’arrêter ; escalader

Ne renvoyez jamais un succès vide sur échec (anti-pattern de silent empty-success).

Référence rapide de décision

SymptômeDiagnosticAction
La boucle ne finit jamaisUtilise la prose/un plafond d’itérations pour s’arrêterBrancher sur stop_reason
JSON tronquémax_tokens atteintAugmenter le plafond / continuer ; valider
« Ça s’est arrêté et mis en pause »pause_turnRenvoyer inchangé
Refus de sécurité traité comme un crashrefusal mal géréRepli explicite
Tempêtes de 429Réessais sans backoff ou ignore retry-afterBackoff + jitter + en-tête ; monter de palier
Réessayer un 400 indéfinimentRéessayer une erreur clientCorriger la requête
Thinking disparu après un repliA basculé vers un modèle plus ancienMigrer uniquement vers plus récent ou équivalent
L’outil a « marché » mais n’a rien renvoyéSuccès videis_error structuré

Idées reçues courantes

Idée reçueRéalitéPourquoi cela compte à l’examen
« Toute erreur devrait être réessayée »Seulement 429/5xx/529 ; corrigez les 4xxDistracteur de tempête de retries
« max_tokens est une réponse complète »C’est une troncatureAnti-pattern de silent-failure
« Parser le texte pour savoir que c’est fini »Brancher sur stop_reasonAnti-pattern de parsing de prose
« Plafonner les itérations pour arrêter la boucle »Le plafond est un garde-fou ; stop_reason l’arrêteAnti-pattern de plafond d’itérations
« refusal est une erreur serveur »C’est un refus de sécurité ; gérez-le explicitementDistracteur de mauvaise gestion de refus
« Un échec d’outil est une erreur API »Les erreurs d’outil utilisent is_error sur le résultatConfusion de couche d’erreur
« 529 signifie abandonner »Backoff ; envisagez un modèle de repliDistracteur de disponibilité

Analyse de scénario

Un agent sur Opus 5 en production, par intermittence : (a) renvoie du JSON coupé, (b) atteint des 529 sous charge, (c) a une fois renvoyé un refus de sécurité montré aux utilisateurs comme « Error 500 », et (d) un ingénieur a ajouté tool_choice: "any" après avoir basculé un flux vers Fable 5.1 et obtient maintenant des 400.

  1. JSON coupé — stop_reason: max_tokens. Augmentez max_tokens et/ou continuez ; validez avant usage.
  2. 529 — réessayable ; backoff exponentiel + jitter respectant retry-after ; après des 529 répétés, basculez vers un modèle plus récent ou équivalent (pas vers le bas).
  3. Refus montré comme 500 — stop_reason: refusal a été mal géré ; routez vers un message de repli explicite, pas une erreur générique.
  4. 400 sur Fable 5.1 — le tool_choice forcé est non supporté (400, non réessayable) ; basculez vers auto+instruction, strict: true, ou output_config.format.

Alternatives rejetées : réessayer le 400 (erreur client — corrigez-la), traiter le JSON tronqué comme valide (silent failure), et présenter le refus comme un 500 (mauvaise gestion de refus).

Points clés à retenir

  • Valeurs de stop_reason : end_turn, tool_use, max_tokens, stop_sequence, pause_turn, refusal — branchez sur chacune.
  • Réessayez 429/5xx/529 avec backoff + jitter + retry-after ; corrigez 400/401/403/404/413.
  • max_tokens = troncature, refusal = refus de sécurité — les deux nécessitent une gestion explicite, pas un laisser-passer silencieux.
  • Les échecs d’outil utilisent un is_error structuré, jamais un succès vide ni une erreur HTTP.
  • Sur des 529 répétés, ne basculez que vers un modèle plus récent ou équivalent pour garder valides les blocs de thinking de Fable 5.1.

Dernière mise à jour le 18 sept. 2026