Erreurs et codes de réponse
Ce que l’API renvoie quand elle refuse, comment le lire, et lesquels de ces refus méritent une nouvelle tentative.
Le format : RFC 7807
Toute erreur porte le même corps, quel que soit le point de terminaison. Il n’y a pas d’objet error imbriqué, et pas de champ code.
{
"type": "about:blank",
"title": "Forbidden",
"status": 403,
"detail": "missing 'keys:wrap' permission"
}title reprend la classe d’erreur, status le code HTTP, detail le motif précis. C’est detail qui distingue les trois cas de 403, et c’est donc lui qu’il faut journaliser.
Le seul symbole : E_ENVELOPE_ONLY
Une seule erreur porte un identifiant symbolique, et il vit dans detail, pas dans un champ dédié. C’est de loin celle que vous rencontrerez le plus souvent en intégrant.
{
"type": "about:blank",
"title": "Forbidden",
"status": 403,
"detail": "E_ENVELOPE_ONLY: ce locataire est en mode enveloppe, ou la donnee
en clair ne transite jamais par MAFATE. Les operations serveur
/v1/encrypt et /v1/decrypt sont donc refusees. Chiffrez en local
avec une cle de donnees et utilisez /v1/keys/{id}/wrap et
/v1/keys/{id}/unwrap, ou ecrivez a [email protected] pour activer
le mode serveur sur ce locataire."
}Ce refus est journalisé sous l’action envelope_only.refused, avec le chemin et la méthode. Réessayer en boucle ne débloque rien et remplit votre journal d’audit de refus : c’est un état de compte, pas un incident passager.
Les huit réponses possibles
Bad RequestJSON malformé, champ requis absent, base64 non conforme, ou clé de données qui ne fait pas exactement 32 octets.
Corriger la requête. Ne pas réessayer : le résultat sera identique. Le contrôle des 32 octets est strict par choix, accepter 16 octets dégraderait silencieusement l’AES-256 annoncé.
UnauthorizedClé API absente, inconnue, expirée ou révoquée. Également renvoyé si le locataire de la clé est introuvable.
Vérifier l’en-tête Authorization et l’état de la clé dans votre tableau de bord.
ForbiddenTrois situations distinctes partagent ce statut : permission manquante sur la clé API, jeton wrapped_key non authentifiable pour la clé visée, ou appel à /v1/encrypt et /v1/decrypt sur un locataire en mode enveloppe.
Lire le champ detail, qui les distingue. Aucune des trois ne se résout en réessayant.
Not FoundLa clé n’existe pas pour ce locataire.
Vérifier que vous passez bien l’UUID rendu par POST /v1/keys, et non le nom lisible de la clé. C’est la cause la plus fréquente de ce statut.
ConflictNom de clé déjà pris sur le locataire, ou opération refusée par l’état de la clé : seule une clé active peut tourner, emballer ou hacher.
Sur une clé désactivée, ce statut est définitif : la destruction des clés de données est irréversible.
Decryption FailedMode serveur uniquement. Le chiffré a été altéré, la clé ne correspond pas, ou le tag GCM ne vérifie pas.
En mode enveloppe, l’équivalent se produit chez vous, à la vérification du tag, sans appel réseau.
Quota ExceededQuota mensuel d’opérations atteint. Uniquement sur /v1/encrypt.
Ce n’est pas une limite de débit et attendre quelques secondes ne changera rien. Le déchiffrement, lui, n’est jamais refusé pour cause de quota : un quota ne doit pas vous enfermer hors de vos propres données.
Internal Server ErrorErreur interne. Un cas mérite d’être connu : unwrap refuse de rendre la clé de données si son entrée d’audit n’a pas pu être écrite.
Ce refus est délibéré, pas un incident de plus : sans trace confirmée, une sortie de clé serait invisible. Le message est explicite, « unwrap refused: audit trail could not be recorded ».
Que réessayer, et que ne pas réessayer
La règle tient en une phrase : réessayez ce que le serveur n’a pas décidé.
| Situation | Réessayer ? |
|---|---|
| Réseau coupé, délai dépassé, aucune réponse | Oui, avec temporisation exponentielle |
| 500, 502, 503 | Oui, sauf le refus d’audit d’unwrap, qui persistera tant que la base n’écrit pas |
| 4xx, quel qu’il soit, y compris 429 | Non. Une décision ne devient pas un accord à la troisième tentative. |
Côté SDK, la distinction est portée par des classes distinctes : ApiError quand le serveur a répondu, avec status, title et detail ; ConnectionError et TimeoutError quand il n’a rien répondu, donc sans statut à interpréter. Les confondre pousse à réessayer là où il faut corriger une configuration, ou l’inverse.