Error 429 en Discord: qué es el rate limit y cómo evitarlo

El error 429 Too Many Requests es Discord pidiéndole a tu bot que espere el tiempo del header Retry-After antes de reintentar. Insistir sin esperar puede bloquear tu IP temporalmente.

Actualizado el 6 min de lectura

Objetivos de aprendizaje

Después de leer este artículo podrás:

  • Entender los tres tipos de límite: por ruta, global y de peticiones inválidas
  • Leer los headers y el cuerpo de una respuesta 429
  • Corregir y evitar el rate limit en discord.js y discord.py
En esta página

Miras la consola de tu bot y ves esto:

json
{
  "message": "You are being rate limited.",
  "retry_after": 1.337,
  "global": false
}

Es el cuerpo de una respuesta HTTP con estado 429 Too Many Requests. Discord limita cuántas llamadas puede hacer cada bot a su API, y el tuyo se pasó. Casi siempre la biblioteca ya espera sola y el bot sigue funcionando.

El caso grave es cuando el bot ignora el aviso, acumula respuestas de error y Discord bloquea la IP por un tiempo. Ese bloqueo temporal es lo que la propia documentación de Discord llama "Cloudflare ban".

BotpeticiónAPI deDiscord200 OK429Retry-AfterEsperael tiempo pedidoreintentaPeticiones inválidas: 401, 403, 42910.000 en 10 minIPbloqueada
Esperar el Retry-After y reintentar resuelve el 429; reintentar sin esperar llena el contador de inválidas hasta bloquear la IP.

¿Cuáles son los límites de Discord?#

Hay tres mecanismos distintos, y confundirlos genera la mayoría de las dudas.

  • Límite por ruta. Cada endpoint tiene su propio bucket. Enviar mensajes en un canal tiene un límite, editar un canal tiene otro. Los valores cambian y Discord pide que no los fijes en el código: lee los headers.
  • Límite global. Hasta 50 peticiones por segundo por bot. Sin el header Authorization, el límite se aplica por IP. Los endpoints de interacción (respuestas a slash commands) no cuentan.
  • Límite de peticiones inválidas. Las respuestas 401, 403 y 429 cuentan como inválidas. Si pasas de 10.000 en 10 minutos, la IP se bloquea temporalmente. Un 429 con X-RateLimit-Scope: shared (límite de un recurso compartido) no cuenta.

También existe el límite del Gateway, la conexión WebSocket: 120 eventos enviados por conexión cada 60 segundos. Si te pasas, Discord desconecta el bot al instante.

¿Cómo se lee una respuesta 429?#

Los headers que importan:

Header Qué informa
Retry-After Cuánto esperar antes de reintentar
X-RateLimit-Remaining Peticiones restantes en el bucket
X-RateLimit-Reset-After Segundos hasta que el bucket se renueva (admite decimales)
X-RateLimit-Bucket ID del bucket, útil para agrupar rutas
X-RateLimit-Global Presente solo cuando se alcanzó el límite global
X-RateLimit-Scope user, global o shared, solo en respuestas 429

El cuerpo JSON trae message, retry_after (segundos, con decimales) y global. Si global es true, todo el bot está detenido, no solo una ruta.

¿Por qué mi bot recibe 429?#

De la causa más común a la menos común:

  1. Bucles sin pausa. Renombrar 200 canales, dar un rol a todos los miembros o borrar mensajes uno por uno, todo de golpe.
  2. Edición constante de mensajes. Un "contador en vivo" o barra de progreso que edita cada segundo choca con el límite de la ruta de mensajes.
  3. Demasiados eventos que disparan llamadas. Un bot que responde a cada mensaje de un servidor con mucha actividad o reacciona a cada evento con una llamada a la API.
  4. Reintento ciego. Una llamada falla, el código reintenta de inmediato y cada intento se convierte en otro 429.
  5. Token inválido en bucle de reinicio. El bot arranca, recibe un 401, se cae, se reinicia y repite. Cada ciclo suma peticiones inválidas. Mira el artículo sobre el token del bot.
  6. Demasiadas reconexiones al Gateway. El límite es de 1.000 llamadas IDENTIFY cada 24 horas. Si lo superas, Discord termina las sesiones del bot y restablece el token.

¿Cómo se corrige el error 429?#

En discord.js (v14)#

La biblioteca ya espera cada rate limit por su cuenta. Tu tarea es vigilar los límites y reducir el volumen. Este fragmento registra cada límite alcanzado y avisa cuando se acumulan respuestas inválidas:

js
import { Client, GatewayIntentBits, RESTEvents } from "discord.js";

const client = new Client({
  intents: [GatewayIntentBits.Guilds],
  rest: {
    // avisa cada 500 respuestas 401/403/429 en la ventana de 10 minutos
    invalidRequestWarningInterval: 500,
  },
});

client.rest.on(RESTEvents.RateLimited, (info) => {
  console.warn(
    `429 en ${info.method} ${info.route}: espera de ${info.timeToReset} ms (global: ${info.global})`,
  );
});

client.rest.on(RESTEvents.InvalidRequestWarning, (info) => {
  console.warn("Demasiadas peticiones inválidas:", info);
});

await client.login(process.env.DISCORD_TOKEN);

La opción rejectOnRateLimit (una función que recibe los datos del límite y devuelve true, como () => true, o una lista de rutas) hace que la biblioteca lance un RateLimitError en lugar de esperar, útil para un comando que prefiere responder "inténtalo en un momento" a quedarse en la cola. Dos valores por defecto que conviene conocer: globalRequestsPerSecond viene en 50, el límite global de Discord, y el aviso de invalidRequestWarningInterval viene desactivado (0).

En discord.py (2.x)#

discord.py también espera por su cuenta y, por defecto, sin tope de espera. Puedes fijar uno con max_ratelimit_timeout (mínimo 30 segundos, solo límites no globales); por encima de eso, la biblioteca lanza discord.RateLimited, con el tiempo en retry_after:

python
import asyncio
import os

import discord

intents = discord.Intents.default()
client = discord.Client(intents=intents, max_ratelimit_timeout=30.0)


async def renombrar_canales(canales: list[discord.TextChannel]) -> None:
    for canal in canales:
        try:
            await canal.edit(name=f"{canal.name}-archivo")
        except discord.RateLimited as error:
            print(f"Límite alcanzado, esperando {error.retry_after:.1f}s")
            await asyncio.sleep(error.retry_after)
            await canal.edit(name=f"{canal.name}-archivo")  # reintenta una vez
        await asyncio.sleep(1)  # pausa entre elementos del lote


client.run(os.environ["DISCORD_TOKEN"])

Lo que vale para cualquier biblioteca#

  • Respeta Retry-After. No reintentes antes de tiempo. Si haces peticiones HTTP a mano, lee el header y espera.
  • Procesa los lotes con intervalo. Una cola con pausa entre elementos cuesta segundos y evita el problema.
  • Edita menos. Actualiza un panel cada 10 o 30 segundos, no cada segundo.
  • Usa endpoints en lote cuando existan. Borrar muchos mensajes tiene su propio endpoint (bulk delete), en lugar de una llamada por mensaje.
  • No repitas 401 ni 403. Un token inválido o la falta de permisos no se arreglan reintentando. Corrige la causa.

¿Qué es el bloqueo temporal de Cloudflare?#

Si tu IP pasa de 10.000 peticiones inválidas en 10 minutos, Discord bloquea temporalmente esa IP en la API. Eso equivale a unas 16 o 17 inválidas por segundo, de forma sostenida, algo que ocurre con bucles de reinicio y reintentos sin pausa, no con un uso normal.

Si sospechas que hay un bloqueo:

  1. Detén el bot. Cada intento nuevo solo alimenta el contador.
  2. Averigua qué generaba las respuestas 401, 403 y 429. Los logs muestran la ruta.
  3. Corrige el bucle y espera a que el bloqueo expire.
  4. Vuelve a arrancar el bot con invalidRequestWarningInterval activado, como en el ejemplo anterior.

¿Cómo saber si es rate limit u otro problema?#

  • 429 con retry_after pequeño: rate limit normal, la biblioteca lo resuelve.
  • 429 con global: true repetido: superaste las 50 peticiones por segundo. Busca el bucle.
  • 401 repetido: token incorrecto o restablecido.
  • 403 repetido: el bot no tiene permiso en ese canal o rol. Compruébalo antes de llamar.
  • Todas las llamadas fallan a la vez: posible bloqueo de IP.
  • El bot se cae y se reinicia sin parar: mira por qué tu bot se queda offline.

Cómo hacerlo en Square Cloud#

El rate limit es una regla de la API de Discord y vale en cualquier hosting. Lo que cambia según el hosting es qué tan rápido detectas el problema. En Square Cloud, los logs se muestran en tiempo real en el panel, la CLI y VS Code, así que un aviso de peticiones inválidas aparece mientras el bot está en marcha.

El reinicio automático, opcional y activado por defecto al hacer el deploy desde el panel, trae el bot de vuelta cuando el proceso termina con error. Eso mantiene el bot en línea, pero con un token inválido cada reinicio puede generar otra respuesta 401, como en el bucle descrito arriba. Maneja el error de login en tu código: registra un mensaje claro en el log, no repitas el intento y corrige el token en las variables de entorno antes de reiniciar.

Los bots de Discord corren en contenedores aislados, con discord.js, discord.py, JDA, Discord.Net u otra biblioteca de Gateway, y la latencia media hasta el Gateway de Discord es de unos 30 ms. El deploy se hace por subida de ZIP, CLI, GitHub o la extensión de VS Code, y el token vive en las variables de entorno de la aplicación. Los detalles están en hosting para bots de Discord. Para poner en marcha tu primer bot, sigue la guía de cómo alojar un bot de discord.js.

Hosting de bots

Tu bot en línea 24/7, con reinicio automático

Más información

Preguntas frecuentes

¿Cuánto dura un error 429 en Discord?

La propia respuesta lo indica, en el header Retry-After y en el campo retry_after del JSON, en segundos. Espera ese tiempo y vuelve a intentar.

¿Cuál es el límite global de peticiones de Discord?

Cada bot puede hacer hasta 50 peticiones por segundo a la API REST. Además, cada ruta tiene su propio límite, que lees en los headers X-RateLimit-*.

¿Pueden banear un bot por errores 429?

Sí. Las respuestas 401, 403 y 429 cuentan como peticiones inválidas, y 10.000 de ellas en 10 minutos hacen que Discord bloquee temporalmente la IP. Un 429 con X-RateLimit-Scope shared no cuenta.

¿discord.js y discord.py manejan el 429 solos?

Sí, ambos esperan el rate limit por defecto. El problema aparece cuando tu código genera demasiado volumen, repite llamadas que fallan o se reinicia en bucle con un token inválido.

Siguiente artículoCómo hospedar un bot de Discord con Node.jsPara hospedar un bot de discord.js, crea la app en el Portal, guarda el token en una variable de entorno y ejecuta el proceso en una máquina siempre encendida.