Error 429 Too Many Requests en APIs de IA: Causas y Solución
¿Error 429 al llamar a la API de OpenAI, Anthropic o Google? Causas técnicas, código para solucionarlo con retry y backoff exponencial, y límites por proveedor.
Tabla de contenidos
Estás desarrollando tu app, los tests pasan, todo funciona… y de repente:
Error 429: Too Many Requests
Rate limit reached for gpt-4.1 in organization org-xxx on tokens per min (TPM):
Limit 30000, Used 28500, Requested 2000.
Tu app se para. Tus usuarios ven errores. Y tú no sabes si es un bug, si has gastado demasiado o si te están bloqueando.
Es el Error 429. El error más común (y más frustrante) al trabajar con APIs de IA. En este artículo te explico por qué ocurre y te doy código listo para solucionarlo.
¿Qué significa el Error 429 Too Many Requests?
El código HTTP 429 significa que el servidor rechaza tu petición porque has superado un límite de uso (rate limit). No es un bug de tu código ni un problema del servidor — es un mecanismo de protección.
En las APIs de IA, los límites existen por:
- Proteger la infraestructura — los modelos de IA consumen GPU caras
- Garantizar servicio equitativo — que un usuario no acapare todos los recursos
- Controlar costes — evitar facturas sorpresa por bucles infinitos
¿Por qué ocurre? Las 4 causas técnicas
1. Rate limit por peticiones (RPM)
Has hecho demasiadas peticiones en un minuto. Cada proveedor tiene un límite de Requests Per Minute (RPM).
// ❌ Esto dispara el 429: 100 peticiones simultáneas
const promises = urls.map(url => openai.chat.completions.create({...}));
await Promise.all(promises); // 💥 429
2. Rate limit por tokens (TPM)
Has enviado demasiados tokens en un minuto. Aunque hagas pocas peticiones, si cada una lleva un contexto de 50K tokens, puedes superar el límite de Tokens Per Minute (TPM).
// ❌ Enviar un archivo enorme como contexto
const context = fs.readFileSync('codebase-entero.txt', 'utf-8'); // 100K tokens
await openai.chat.completions.create({
messages: [{ role: 'user', content: context + '\nResume esto' }],
}); // 💥 429 por TPM
3. Cuota mensual agotada
Has gastado el presupuesto que tu cuenta permite. OpenAI y Anthropic tienen límites de gasto mensual por tier. Si estás en Tier 1 y tu límite es $100/mes, al llegar a esa cifra obtienes un 429 hasta el siguiente ciclo.
4. Peticiones concurrentes excesivas
Algunos proveedores limitan cuántas peticiones pueden estar procesándose a la vez. Si lanzas 50 llamadas simultáneas y el límite es 25, las que sobren reciben un 429.
Solución paso a paso
Paso 1: Identifica qué límite estás superando
El Error 429 viene con headers que te dicen qué está pasando:
try {
const response = await openai.chat.completions.create({...});
} catch (error) {
if (error.status === 429) {
console.log('Tipo:', error.headers['x-ratelimit-limit-requests']);
console.log('Restantes:', error.headers['x-ratelimit-remaining-requests']);
console.log('Reset en:', error.headers['x-ratelimit-reset-requests']);
console.log('Retry-After:', error.headers['retry-after']);
}
}
| Header | Qué indica |
|---|---|
x-ratelimit-limit-requests | Tu límite de RPM |
x-ratelimit-remaining-requests | Peticiones que te quedan |
x-ratelimit-limit-tokens | Tu límite de TPM |
x-ratelimit-remaining-tokens | Tokens que te quedan |
retry-after | Segundos que debes esperar |
Paso 2: Implementa retry con backoff exponencial
La solución estándar: si recibes un 429, espera y reintenta. Cada reintento duplica el tiempo de espera para no saturar el servidor.
async function callWithRetry(fn, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (error.status !== 429 || attempt === maxRetries - 1) {
throw error;
}
// Backoff exponencial: 1s, 2s, 4s, 8s, 16s
const retryAfter = error.headers?.['retry-after'];
const delay = retryAfter
? parseInt(retryAfter) * 1000
: Math.pow(2, attempt) * 1000 + Math.random() * 1000;
console.log(`429 recibido. Reintentando en ${Math.round(delay / 1000)}s...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Uso
const response = await callWithRetry(() =>
openai.chat.completions.create({
model: 'gpt-4.1',
messages: [{ role: 'user', content: 'Hola' }],
})
);
El + Math.random() * 1000 (jitter) es importante: evita que múltiples instancias de tu app reintenten al mismo tiempo y vuelvan a saturar el límite.
Paso 3: Controla el flujo de peticiones (rate limiter)
Si haces muchas llamadas (scraping, procesamiento masivo, agentes), necesitas un rate limiter que controle cuántas peticiones se envían por minuto.
class RateLimiter {
constructor(maxPerMinute) {
this.maxPerMinute = maxPerMinute;
this.queue = [];
this.timestamps = [];
}
async acquire() {
const now = Date.now();
this.timestamps = this.timestamps.filter(t => now - t < 60000);
if (this.timestamps.length >= this.maxPerMinute) {
const waitTime = 60000 - (now - this.timestamps[0]);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
this.timestamps.push(Date.now());
}
}
// Uso: máximo 50 peticiones/minuto
const limiter = new RateLimiter(50);
async function callAPI(prompt) {
await limiter.acquire();
return openai.chat.completions.create({
model: 'gpt-4.1-mini',
messages: [{ role: 'user', content: prompt }],
});
}
// Procesar 500 items sin 429
for (const item of items) {
const result = await callAPI(item.text);
// ...
}
Paso 4: Optimiza tokens para gastar menos cuota
Menos tokens = menos probabilidad de alcanzar el TPM.
// ❌ System prompt de 500 tokens
system: "Eres un asistente altamente cualificado experto en... [párrafo enorme]"
// ✅ System prompt de 30 tokens
system: "Senior dev. Responde en español. Solo código, sin explicación."
// ❌ Enviar todo el archivo
content: entireFileContent // 50K tokens
// ✅ Enviar solo lo relevante
content: extractRelevantChunk(entireFileContent, query) // 2K tokens
Paso 5: Cachea respuestas repetidas
Si haces la misma pregunta varias veces, no llames a la API de nuevo.
const cache = new Map();
async function cachedCompletion(prompt, model = 'gpt-4.1-mini') {
const key = `${model}:${prompt}`;
if (cache.has(key)) {
return cache.get(key);
}
const response = await callWithRetry(() =>
openai.chat.completions.create({
model,
messages: [{ role: 'user', content: prompt }],
})
);
const result = response.choices[0].message.content;
cache.set(key, result);
return result;
}
Para producción, sustituye el Map() por Redis o un archivo JSON persistente.
Límites reales por proveedor en 2026
Estos son los límites con los que te vas a encontrar:
OpenAI
| Tier | RPM (GPT-4.1) | TPM (GPT-4.1) | Gasto mensual máx. |
|---|---|---|---|
| Free | 3 | 40.000 | — |
| Tier 1 ($5+ gastados) | 500 | 200.000 | $100 |
| Tier 2 ($50+) | 5.000 | 2.000.000 | $500 |
| Tier 3 ($100+) | 5.000 | 4.000.000 | $1.000 |
| Tier 5 ($1.000+) | 10.000 | 30.000.000 | $5.000 |
Anthropic (Claude)
| Tier | RPM | TPM input | TPM output |
|---|---|---|---|
| Free (Build) | 5 | 20.000 | 8.000 |
| Tier 1 ($5+) | 50 | 80.000 | 16.000 |
| Tier 2 ($40+) | 1.000 | 160.000 | 32.000 |
| Tier 3 ($200+) | 2.000 | 320.000 | 64.000 |
| Tier 4 ($400+) | 4.000 | 640.000 | 128.000 |
Google (Gemini)
| Plan | RPM | TPM | Precio |
|---|---|---|---|
| AI Studio (gratis) | 15 | 1.000.000 | $0 |
| AI Studio (pay-as-you-go) | 2.000 | 4.000.000 | Variable |
| Vertex AI | 1.000+ | Configurable | Variable |
DeepSeek
| Plan | RPM | TPM |
|---|---|---|
| API estándar | 60 | 500.000 |
| Con saldo > $10 | 300 | 2.000.000 |
Cuándo la solución es cambiar de proveedor
A veces el 429 te está diciendo que necesitas otro approach:
| Situación | Solución |
|---|---|
| Necesitas >2.000 RPM y estás en Tier 1 de OpenAI | Gasta más para subir a Tier 2+, o usa Google AI Studio (2.000 RPM pay-as-you-go) |
| Procesas datos masivos (10K+ documentos) | Usa Batch API de OpenAI (50% descuento + sin rate limit con cola) |
| Tu app tiene picos impredecibles | Distribuye entre proveedores: OpenAI + Anthropic + Google |
| No puedes permitirte rate limits | Ejecuta modelos locales con Ollama (sin límites) |
| Haces muchas peticiones idénticas | Prompt Caching (90% descuento en tokens cacheados) |
Si estás evaluando costes, consulta la calculadora de precios de IA para comparar todos los proveedores. Y si buscas opciones sin coste, mira cómo usar la API de ChatGPT y Claude gratis. Si el error ocurre en tu extensión de VS Code, consulta los 5 errores comunes con Copilot, Cline y Cursor.
Este error también está documentado en el índice de errores comunes en desarrollo, donde encontrarás guías para otros errores frecuentes como CORS y ENOENT.
Solución completa: wrapper robusto para producción
Aquí tienes una clase que combina retry, rate limiting y cache. Lista para copiar en tu proyecto:
import OpenAI from 'openai';
class RobustAIClient {
constructor({ apiKey, maxRPM = 50, maxRetries = 5 }) {
this.client = new OpenAI({ apiKey });
this.maxRetries = maxRetries;
this.timestamps = [];
this.maxRPM = maxRPM;
this.cache = new Map();
}
async rateLimit() {
const now = Date.now();
this.timestamps = this.timestamps.filter(t => now - t < 60000);
if (this.timestamps.length >= this.maxRPM) {
const wait = 60000 - (now - this.timestamps[0]);
await new Promise(r => setTimeout(r, wait));
}
this.timestamps.push(Date.now());
}
async chat(prompt, { model = 'gpt-4.1-mini', useCache = true } = {}) {
const cacheKey = `${model}:${prompt}`;
if (useCache && this.cache.has(cacheKey)) return this.cache.get(cacheKey);
await this.rateLimit();
for (let attempt = 0; attempt < this.maxRetries; attempt++) {
try {
const res = await this.client.chat.completions.create({
model,
messages: [{ role: 'user', content: prompt }],
});
const result = res.choices[0].message.content;
if (useCache) this.cache.set(cacheKey, result);
return result;
} catch (err) {
if (err.status !== 429 || attempt === this.maxRetries - 1) throw err;
const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
console.warn(`429 → retry ${attempt + 1}/${this.maxRetries} en ${Math.round(delay / 1000)}s`);
await new Promise(r => setTimeout(r, delay));
}
}
}
}
// Uso
const ai = new RobustAIClient({
apiKey: process.env.OPENAI_API_KEY,
maxRPM: 100,
});
const answer = await ai.chat('Explica qué es un rate limiter');
Si estás construyendo agentes que hacen múltiples llamadas, este wrapper te evitará el 429 en el 99% de los casos. Para un ejemplo real de agente en producción, sigue mi tutorial de agente con LangChain y Node.js.
Checklist rápido anti-429
- ¿Tienes retry con backoff exponencial + jitter?
- ¿Controlas el RPM con un rate limiter?
- ¿Cacheas respuestas repetidas?
- ¿Usas el modelo más pequeño posible para cada tarea?
- ¿Limitas
max_tokensen cada petición? - ¿Envías solo el contexto necesario (no archivos enteros)?
- ¿Sabes en qué tier estás y cuáles son tus límites?
- ¿Tienes un fallback a otro proveedor si el principal falla?
Si marca todos: el Error 429 no debería volver a pararte.
¿Te ha funcionado? Si conoces otro truco para manejar rate limits o has encontrado un caso raro de 429, compártelo en LinkedIn o visita mi portfolio para ver proyectos donde gestiono miles de llamadas a APIs de IA en producción.