Une erreur 429 sur OpenRouter ne signifie pas forcément que votre compte a atteint sa limite. Le fournisseur d’inférence sélectionné peut lui aussi limiter vos requêtes. Avant toute modification, conservez une réponse d’échec complète : le statut HTTP, les en-têtes et le corps JSON permettent d’identifier précisément la limite concernée.
Avant toute modification, analysez une réponse 429
Ne vous précipitez pas pour acheter des crédits, remplacer votre clé ou ajouter des tentatives automatiques. Les champs typés d’OpenRouter et les en-têtes de réponse constituent des indices bien plus fiables que le message lisible, qui peut reprendre un texte transmis par un fournisseur en amont.
| Indice | Origine la plus probable | Action à mener |
|---|---|---|
HTTP 429 avec X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset | Limite de la plateforme OpenRouter | Attendez la réinitialisation, puis réduisez le débit ou la concurrence |
error.metadata.error_type vaut rate_limit_exceeded, avec des détails tels que provider_code | Fournisseur en amont | Attendez, autorisez un autre fournisseur ou utilisez un modèle de repli |
Présence de Retry-After | Tous les fournisseurs tentés ont fourni une indication de délai | Attendez cet intervalle avant la tentative suivante |
| HTTP 402 | Solde insuffisant ou plafond de crédit par clé épuisé | Ajoutez des crédits ou modifiez le plafond de la clé ; le backoff ne résoudra rien |
HTTP 200, puis erreur SSE avec finish_reason: "error" | Échec après le début du streaming | Considérez le flux comme échoué et examinez le type d’erreur intégré |
La référence OpenRouter sur les erreurs et le débogage décrit l’enveloppe contenant error.code, error.message et l’éventuel error.metadata, y compris error_type = "rate_limit_exceeded". Elle précise également que les réponses réussies n’incluent normalement pas les en-têtes X-RateLimit-*. La surcharge d’un fournisseur est distinguée via provider_overloaded et correspond normalement à un statut 503.
Résoudre une erreur 429 au niveau d’OpenRouter
Une 429 émise par OpenRouter dépend du quota de la plateforme associé au compte et à la catégorie de modèle. D’après la documentation officielle sur les limites de débit, vérifiée le 31 juillet 2026, les variantes de modèles gratuits se terminant par :free sont soumises à des plafonds par minute et par jour.
| Quota des modèles gratuits | Limite actuelle |
|---|---|
| Requêtes par minute | 20 RPM |
| Requêtes quotidiennes avec moins de 10 $ d’achats de crédits cumulés | 50 RPD |
| Requêtes quotidiennes avec au moins 10 $ d’achats de crédits cumulés | 1,000 RPD |
La politique de limites indique que des comptes ou des clés supplémentaires n’augmentent pas une capacité gérée globalement. Remplacer une clé valide ne réinitialise donc pas une limite de débit de la plateforme.
Utilisez le point de terminaison GET /api/v1/key pour consulter l’utilisation et les limites de crédit :
curl https://openrouter.ai/api/v1/key \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
Face à une 429 de la plateforme, appuyez-vous sur l’en-tête de réinitialisation de la réponse d’erreur et procédez dans cet ordre :
- Arrêtez les nouvelles tentatives immédiates et attendez jusqu’à
X-RateLimit-Reset. - Réduisez le nombre de requêtes simultanées, pas seulement les requêtes par seconde. Une rafale de workers parallèles peut franchir la limite avant que le premier n’aperçoive la 429.
- Placez les tâches derrière un limiteur partagé afin que tous les workers ne se réveillent pas et ne réessaient pas au même instant.
- Si votre charge ne tient pas dans le quota des modèles gratuits, basculez ce trafic vers une variante de modèle payante adaptée.
Un solde négatif ou un plafond de crédit par clé épuisé doit produire une 402, tandis qu’un fournisseur en amont peut toujours renvoyer une 429 à un compte approvisionné. Le guide tarifaire OpenRouter traite séparément des questions de coût et de crédits.
Résoudre une 429 « Provider Returned Error »
Une 429 renvoyée par un fournisseur signifie qu’OpenRouter a contacté un fournisseur d’inférence en amont qui ne pouvait pas accepter la requête à cet instant. Vérifiez la valeur typée de limitation ainsi que les métadonnées du fournisseur : ajouter des crédits OpenRouter ne crée pas de capacité chez ce fournisseur.
La référence officielle sur les limites explique que le routage a peut-être déjà essayé des fournisseurs alternatifs avant de renvoyer l’erreur. Elle ajoute également Retry-After lorsque tous les fournisseurs tentés ont fourni une indication de délai. En pratique :
- Respectez
Retry-Afterau lieu de régénérer immédiatement la même requête. - Supprimez les restrictions trop strictes sur les fournisseurs si elles ne laissent qu’une seule route saturée.
- Vérifiez que le repli vers un autre fournisseur est autorisé pour la requête.
- Configurez un modèle de repli lorsque l’exécution de la tâche compte davantage que l’utilisation du modèle exact.
Un utilisateur Zed disposant de crédits a rencontré une limite en amont sur moonshotai/kimi-k2:free, et régénérer la clé n’a rien changé. Un contributeur de Zed a expliqué :
« Ce n’est pas une erreur Zed : OpenRouter vous indique que le fournisseur en amont que vous utilisez applique une limitation de débit. » Source : zed-industries/zed issue #35153
Respectez un Retry-After court ; n’utilisez un modèle gratuit de repli que si terminer la tâche importe plus que conserver le modèle précis.
Si l’erreur survient dans Janitor AI, Zed ou SillyTavern
Conservez l’erreur brute, évitez de régénérer plusieurs fois et changez de modèle ou de route autorisée en cas d’échec côté fournisseur. Ne ressaisissez une clé que pour corriger son stockage dans le client : cela ne réinitialise aucune capacité.
Réessayer sans déclencher une boucle de 429
Ne relancez que les erreurs de limitation, plafonnez le nombre de tentatives et privilégiez le délai demandé par le serveur. En l’absence d’indication, appliquez un backoff exponentiel plafonné avec jitter afin que les clients parallèles ne se synchronisent pas dans une nouvelle rafale.
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function retryDelayMs(response, attempt) {
const retryAfter = response.headers.get("retry-after");
if (retryAfter) {
const seconds = Number(retryAfter);
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);
const dateMs = Date.parse(retryAfter);
if (Number.isFinite(dateMs)) return Math.max(0, dateMs - Date.now());
}
const capMs = 30_000;
const exponentialMs = Math.min(capMs, 1000 * 2 ** attempt);
return Math.random() * exponentialMs; // Full jitter
}
async function createChatCompletion(body, maxAttempts = 4) {
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
const response = await fetch(
"https://openrouter.ai/api/v1/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
},
);
const raw = await response.text();
let payload;
try {
payload = raw ? JSON.parse(raw) : null;
} catch {
payload = null;
}
if (response.ok) return payload;
const isRateLimit =
response.status === 429 ||
payload?.error?.metadata?.error_type === "rate_limit_exceeded";
if (!isRateLimit || attempt === maxAttempts - 1) {
const error = new Error(payload?.error?.message || raw || `HTTP ${response.status}`);
error.status = response.status;
error.details = payload?.error;
throw error;
}
await sleep(retryDelayMs(response, attempt));
}
}
Cette fonction gère les réponses hors streaming. Ajoutez le contrôle de concurrence, par file partagée ou token bucket, en dehors de celle-ci afin que de nombreux workers en attente ne redémarrent pas tous ensemble.
Une fois les Server-Sent Events lancés avec HTTP 200, le statut ne peut plus devenir 429. La référence des erreurs OpenRouter indique qu’un échec ultérieur est transmis dans le flux sous forme d’erreur avec finish_reason: "error". Marquez alors la complétion comme échouée et ne réessayez que si le type intégré est rate_limit_exceeded. Ne retournez pas le texte déjà accumulé comme un succès, sauf si l’application prend explicitement en charge les résultats partiels.
FAQ
Que signifie l’erreur 429 « provider returned error » dans OpenRouter ?
Un fournisseur d’inférence en amont a refusé la requête en raison de sa propre limite de débit ou de capacité. Confirmez-le avec error.metadata.error_type et les métadonnées du fournisseur.
Pourquoi OpenRouter renvoie-t-il une 429 alors qu’il me reste des crédits ?
Un compte approvisionné peut recevoir une 429 côté fournisseur ; un solde insuffisant ou un plafond de crédit par clé correspond normalement à une 402.
Créer une nouvelle clé API OpenRouter réinitialise-t-il la limite de débit ?
Non. Des clés supplémentaires n’augmentent pas les limites gérées globalement ; remplacez-en une uniquement pour résoudre un problème d’authentification ou de stockage côté client.
Combien de temps attendre avant de réessayer OpenRouter ?
Utilisez Retry-After lorsqu’il est présent. Pour une limite de plateforme, utilisez X-RateLimit-Reset ; sans l’une ou l’autre indication, appliquez un backoff exponentiel plafonné avec jitter et un faible nombre maximal de tentatives.
OpenRouter peut-il renvoyer HTTP 200 tout en échouant avec une 429 ?
Oui, lorsque le streaming a déjà commencé. Le statut HTTP reste 200, tandis que le flux SSE signale une erreur et se termine par finish_reason: "error" ; examinez le type d’erreur intégré pour déterminer s’il s’agissait d’une limitation de débit.