Skip to content

Erreurs ​

Toute réponse d’erreur de l’API a la même forme, quelle que soit la route et quelle que soit la cause :

json
{
  "code": "workflow.not_publishable",
  "message": "the draft has validation errors",
  "details": {
    "validation": { "ok": false, "errors": [ { "code": "trigger_required", "message": "…" } ], "warnings": [] }
  }
}
ChampSens
codeUn identifiant stable, qui fait partie du contrat. Testez-le, jamais le message.
messageUne description technique en anglais, pour les journaux et le débogage. Il peut changer sans préavis et n’est pas destiné aux utilisateurs finaux.
detailsFacultatif, propre à l’erreur : la portée manquante (required), le délai avant de réessayer (retryAfterSeconds), le diagnostic de validation (validation), la raison d’un échec de lecture (reason)…

L’interface n’affiche jamais message : elle traduit code dans la langue du membre. Votre programme peut faire de même.

Les codes s’écrivent toujours domaine.code ​

Un code, c’est un domaine, un point, et une cause en snake_case : auth.unauthenticated, workflow.not_found, api_key.scope_missing, tables.duplicate_key, request.bad_request. Le domaine désigne la partie du produit ; la cause dit ce qui a échoué. Les codes ne contiennent que des lettres minuscules, des chiffres, _ et ., et exactement un point.

Le domaine permet de traiter une famille d’un coup (startsWith("llm.")) et de retrouver un code dans la liste des codes d’erreur. Les codes propres à une route sont listés sous cette route dans la référence.

Les classes de statut HTTP ​

Le statut donne la classe de l’erreur ; le code donne la cause précise.

StatutClasseCodes typiques
400La requête ne respecte pas son schéma, ou ne se lit pasrequest.bad_request, workflow.invalid_graph, idempotency.invalid_key
401Aucune session ni clé valideauth.unauthenticated
403Authentifié, mais refusé : rôle, portée, politiqueauth.forbidden, api_key.scope_missing, api_key.session_required, webmail.sending_disabled
404Ressource inconnue, ou ressource d’un autre membreworkflow.not_found, execution.not_found, request.not_found
409Un conflit avec l’état actuelworkflow.draft_conflict, workflow.not_publishable, execution.not_cancellable, idempotency.in_progress
413Le corps de la requête dépasse sa limite (5 Mo ; 256 Ko de JSON pour un déclencheur webhook)request.payload_too_large (details.reason: "FST_ERR_CTP_BODY_TOO_LARGE" pour la limite de 5 Mo)
422La requête est bien formée mais ne peut pas être honoréeidempotency.key_reused
429Une limite de débit est atteinte ; Retry-After dit quand réessayerapi_key.rate_limited, auth.too_many_attempts, webmail.rate_limited
500Une erreur inattendue du serveur ; rien de plus n’est dit au clientrequest.internal_error

Une ressource qui existe mais appartient à un autre membre est un 404, jamais un 403 : l’API ne révèle pas ce qu’elle ne vous laisse pas voir.

Les codes communs à toutes les routes ​

CodeStatutQuand
request.bad_request400Le corps ou la requête ne respecte pas le schéma de la route, ou le JSON ne se lit pas.
request.payload_too_large413Le corps dépasse la limite de la route : 5 Mo pour l’API, 256 Ko de JSON pour un déclencheur webhook.
request.not_found404Aucune route ne répond à ce chemin.
request.internal_error500Une erreur que le serveur n’attendait pas. L’identifiant de la requête est dans les journaux du serveur.
auth.unauthenticated401Pas de session, pas de clé, ou une clé inconnue, expirée ou révoquée.
auth.forbidden403Le membre n’a pas le rôle que la route exige.
api_key.scope_missing403Aucune portée de la clé ne couvre la route ; details.required nomme celle à ajouter.
api_key.session_required403La route est réservée à une session de membre.
api_key.route_not_allowed403La route n’est pas ouverte aux clés d’API.
api_key.rate_limited429Plus de 600 requêtes dans la dernière minute avec cette clé.
idempotency.invalid_key400Idempotency-Key est vide ou dépasse 200 caractères.
idempotency.in_progress409La requête d’origine portant cette clé court encore.
idempotency.key_reused422La même clé a servi à une autre requête.

Seuls les premiers figurent sous chaque route du document OpenAPI (les réponses 400, 401, 403 et 429) ; les autres sont implicites pour toute route authentifiée.

Traiter les erreurs dans un client ​

  • Branchez sur code, et sur le statut seulement en repli pour les codes que vous ne connaissez pas encore.
  • Sur 429, respectez Retry-After. Sur 409 idempotency.in_progress, rejouez avec la même Idempotency-Key après une seconde.
  • Sur 403 api_key.scope_missing, le remède est une nouvelle clé avec details.required, pas un nouvel essai.
  • Sur 409 workflow.not_publishable, lisez details.validation.errors : chaque entrée porte le nœud (nodeId) et la raison (code), le même diagnostic que l’éditeur affiche.
  • Journalisez message et details ; montrez à vos utilisateurs un texte à vous, choisi d’après code.