
Une erreur 429 Too Many Requests est le seul code de statut qui parle de vous plutôt que du serveur ou de ce que vous avez demandé. Rien n’est cassé, rien ne manque, et vous avez le droit d’être là. Vous avez simplement demandé plus souvent que ce que quelqu’un a jugé raisonnable, et la réponse est un refus avec une horloge attachée.
Tout le reste de la plage 4xx décrit une requête unique : celle-ci était mal formée, celle-ci n’avait pas d’identifiants, celle-ci ne nommait rien. Une 429 décrit un motif. C’est le serveur qui parle de votre comportement sur une fenêtre de temps, ce qui explique qu’elle puisse arriver en réponse à une requête parfaitement correcte qui aurait fonctionné il y a dix minutes.
La seule erreur où réessayer aggrave les choses
La plupart des erreurs récompensent une nouvelle tentative. Une 503 se règle souvent au deuxième essai, et pour une 500 un rechargement vaut le coup au cas où vous seriez tombé sur un mauvais moment. L’instinct a généralement raison, et ici il a précisément tort.
Un limiteur de débit compte les requêtes. Une nouvelle tentative est une requête. Marteler un service qui vient de vous dire de ralentir allonge la fenêtre pendant laquelle il vous retient et, sur les services qui escaladent, transforme une limite de soixante secondes en une heure ou en un blocage qu’il faut lever à la main. La boucle de retry naïve, celle sans aucun délai dedans, est la façon dont un bridage bref devient une panne qui ressemble à la faute de l’autre côté.
Une 429 est donc l’erreur où ne rien faire est le choix actif. Attendez la fin de la fenêtre, puis réessayez, une fois.
Les en-têtes qui disent quand revenir
Une 429 porte généralement Retry-After, indiquant soit un nombre de secondes soit une date :
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1789412400
Retry-After est celui qui est normalisé et le seul sur lequel vous puissiez compter. La famille
X-RateLimit-* est une convention et non une spécification : très répandue, orthographiée
différemment selon les services, et qui mérite d’être lue quand elle est là, parce qu’elle vous
donne la forme de la limite et pas seulement le prochain instant où vous pourrez frapper.
Ces en-têtes font la différence entre reculer correctement et deviner. Si vous écrivez quoi que ce soit qui parle à une API selon un calendrier, lisez-les : un service qui a dit soixante secondes et qui reçoit une tentative par seconde se voit demander cent vingt fois de servir des requêtes qu’il a déjà refusées.
Quand le trafic n’était pas le vôtre
Le côté délicat d’une 429 est que ce qui est compté est rarement une personne. C’est une adresse IP, une clé d’API, un compte ou une session, et chacun de ces éléments couvre plus d’un vous.
Un bureau derrière une seule adresse, un café, un opérateur mobile qui fait du NAT à grande échelle, un pipeline d’intégration continue partageant une clé avec une équipe, un collègue qui teste un script sur le même point d’accès avec les mêmes identifiants. Tout cela produit une 429 pour quelqu’un qui n’a rien fait d’inhabituel, et rien de tout cela n’est visible depuis la page d’erreur.
D’où le test utile. Si une 429 vous suit d’un réseau à l’autre, c’est votre compte ou votre clé, et si elle disparaît en données mobiles, c’était l’adresse d’où vous veniez. C’est la même question que distinguer votre bug de leur panne, posée à propos d’une limite plutôt que d’une défaillance.
Vous pouvez être bridé sans jamais voir de 429
Rien n’oblige un service à utiliser ce code. Beaucoup renvoient une 403 pour que le bridage ressemble à une décision de permissions, certains renvoient une 503 parce que, vu de l’extérieur, « pas maintenant » est vrai de toute façon, et un CDN devant une application répondra souvent selon son propre choix plutôt que selon celui de l’application.
Une 429 est donc une bonne nouvelle en un sens : c’est un service qui est précis avec vous. Son absence ne prouve pas que vous n’êtes pas bridé, et si une 403 ou une 503 n’apparaît que sous charge et que depuis une seule adresse, un limiteur est ce qu’il faut soupçonner quel que soit le code.
Si c’est votre API
La question à trancher avant tout réglage est de savoir quelle couche compte. Une limite dans votre application, une dans nginx et une au CDN font trois jeux de chiffres différents, et celui que vos utilisateurs heurtent n’est généralement pas celui que vous regardiez.
Ensuite, envoyez les en-têtes. Une 429 sans Retry-After est un service qui refuse de dire quand,
ce qui laisse chaque client inventer son backoff, et ceux qu’ils inventent sont pires que le
nombre que vous leur auriez donné. Être précis ne coûte rien.
Et faites attention à ce que compte la limite. Les limites par IP punissent les bureaux et les réseaux partagés pour le comportement d’une seule personne dedans, ce qui est un ticket de support qui arrive sous la forme « votre site est cassé pour toute notre équipe ». Les limites par compte ou par clé sont plus difficiles à mettre en place et bien plus faciles à expliquer.
Pourquoi une 429 est difficile à reconstituer après coup
Le temps que quelqu’un vous en parle, la fenêtre est passée et la requête fonctionne. Ce qui l’a fait échouer n’était pas la requête mais sa compagnie : les quatre-vingt-dix-neuf autres arrivées dans la même minute, la plupart venant de quelqu’un d’autre, aucune d’elles devant vous maintenant.
Session Replay
Extension Chrome gratuite. Un clic sur la page qui se comporte mal capture la capture d'écran, la console et le journal réseau, et vous donne un lien à coller dans le ticket.
Le journal réseau est ce qui rend une 429 investigable : la requête en échec, la minute exacte, et les en-têtes de réponse disant quelle limite a été atteinte et combien de temps il lui restait à courir. C’est la différence entre un rapport que quelqu’un peut confronter au journal d’un limiteur et un message disant que le site a cessé de marcher un moment ce matin.
En un paragraphe
Une erreur 429 Too Many Requests signifie que vous avez demandé trop souvent, ce qui en fait le
seul code de statut portant sur votre comportement plutôt que sur le serveur ou la ressource.
C’est aussi la seule erreur où réessayer est activement contre-productif, parce qu’une nouvelle
tentative est une requête de plus à compter pour le limiteur : lisez Retry-After, attendez, puis
allez-y une fois. Le trafic compté n’est souvent pas le vôtre, puisque les limites s’appliquent à
des adresses et des clés couvrant des bureaux et des équipes entières, et un téléphone en données
mobiles vous dira auquel des deux vous avez affaire. Si c’est votre API, déterminez quelle couche
compte, envoyez toujours Retry-After, et préférez limiter une clé plutôt qu’une adresse, pour
qu’une seule personne ne puisse pas verrouiller tout un bâtiment.