Erro 429 no Discord: rate limit e ban temporário do Cloudflare

O erro 429 Too Many Requests é o Discord mandando seu bot esperar o tempo do header Retry-After antes de tentar de novo. Insistir sem esperar pode render um bloqueio temporário do IP.

Atualizado em 6 min de leitura

Objetivos de aprendizado

Depois de ler este artigo, você vai conseguir:

  • Entender os três tipos de limite: por rota, global e de requisições inválidas
  • Ler os headers e o corpo de uma resposta 429
  • Corrigir e evitar o rate limit em discord.js e discord.py
Nesta página

Você olha o console do bot e vê isto:

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

É o corpo de uma resposta HTTP com status 429 Too Many Requests. O Discord limita quantas chamadas cada bot pode fazer à API, e você passou do limite. Na maioria dos casos a biblioteca já espera sozinha e o bot segue funcionando.

O caso grave é quando o bot ignora o aviso, acumula respostas de erro e o Discord bloqueia o IP por um tempo. Esse bloqueio temporário é o que a própria documentação do Discord chama de "Cloudflare ban".

BotrequisiçãoAPI doDiscord200 OK429Retry-AfterEsperao tempo pedidorepeteRequisições inválidas: 401, 403, 42910.000 em 10 minIPbloqueado
Esperar o Retry-After e repetir resolve o 429; repetir sem esperar enche o contador de inválidas até o bloqueio do IP.

Quais são os limites do Discord?#

Existem três mecanismos diferentes, e confundir os três gera a maior parte das dúvidas.

  • Limite por rota. Cada endpoint tem um bucket próprio. Enviar mensagens num canal tem um limite, editar um canal tem outro. Os valores mudam e o Discord pede que você não os fixe no código: leia os headers.
  • Limite global. Até 50 requisições por segundo por bot. Sem o header Authorization, o limite vale por IP. Endpoints de interação (respostas a slash commands) não entram nessa conta.
  • Limite de requisições inválidas. Respostas 401, 403 e 429 contam como inválidas. Acima de 10.000 em 10 minutos, o IP é bloqueado temporariamente. Um 429 com X-RateLimit-Scope: shared (limite de um recurso compartilhado) não conta.

Há ainda o limite do Gateway, a conexão WebSocket: 120 eventos enviados por conexão a cada 60 segundos. Acima disso, o Discord desconecta o bot na hora.

Como ler uma resposta 429?#

Os headers que importam:

Header O que informa
Retry-After Tempo de espera antes de tentar de novo
X-RateLimit-Remaining Requisições restantes no bucket
X-RateLimit-Reset-After Segundos até o bucket renovar (aceita decimais)
X-RateLimit-Bucket ID do bucket, útil para agrupar rotas
X-RateLimit-Global Presente só quando o limite global foi atingido
X-RateLimit-Scope user, global ou shared, só em respostas 429

O corpo JSON traz message, retry_after (segundos, com decimais) e global. Se global for true, o bot inteiro está parado, não só uma rota.

Por que meu bot recebe 429?#

Da causa mais comum para a menos comum:

  1. Loops sem pausa. Renomear 200 canais, dar cargo a todos os membros ou apagar mensagens uma a uma, tudo de uma vez.
  2. Edição constante de mensagens. Um "contador ao vivo" ou barra de progresso que edita a cada segundo bate no limite da rota de mensagens.
  3. Muitos eventos gerando chamadas. Um bot que responde a cada mensagem de um servidor movimentado ou reage a cada evento com uma chamada à API.
  4. Retry cego. Quando uma chamada falha, o código repete na hora, sem esperar, e cada tentativa vira mais um 429.
  5. Token inválido em loop de reinício. O bot sobe, recebe 401, cai, reinicia e repete. Cada ciclo soma requisições inválidas. Veja o artigo sobre token do bot.
  6. Reconexões em excesso ao Gateway. O limite é de 1.000 chamadas IDENTIFY por 24 horas. Ao atingir esse limite, o Discord encerra as sessões do bot e redefine o token.

Como corrigir o erro 429?#

No discord.js (v14)#

A biblioteca já espera cada rate limit sozinha. Seu trabalho é observar e reduzir o volume. Este trecho registra cada limite atingido e avisa quando as respostas inválidas se acumulam:

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

const client = new Client({
  intents: [GatewayIntentBits.Guilds],
  rest: {
    // avisa a cada 500 respostas 401/403/429 na janela de 10 minutos
    invalidRequestWarningInterval: 500,
  },
});

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

client.rest.on(RESTEvents.InvalidRequestWarning, (info) => {
  console.warn("Muitas requisições inválidas:", info);
});

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

A opção rejectOnRateLimit (uma função que recebe os dados do limite e retorna true, como () => true, ou uma lista de rotas) faz a biblioteca lançar um RateLimitError em vez de esperar, útil para um comando que prefere responder "tente em instantes" a ficar preso na fila. Dois padrões que vale conhecer: globalRequestsPerSecond vem em 50, o limite global do Discord, e o aviso de invalidRequestWarningInterval vem desligado (0).

No discord.py (2.x)#

O discord.py também espera por conta própria e, por padrão, sem teto de espera. Você pode definir um com max_ratelimit_timeout (mínimo de 30 segundos, só para limites não globais); acima disso, a biblioteca lança discord.RateLimited, com o tempo em 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 renomear_canais(canais: list[discord.TextChannel]) -> None:
    for canal in canais:
        try:
            await canal.edit(name=f"{canal.name}-arquivo")
        except discord.RateLimited as erro:
            print(f"Limite atingido, esperando {erro.retry_after:.1f}s")
            await asyncio.sleep(erro.retry_after)
            await canal.edit(name=f"{canal.name}-arquivo")  # tenta de novo uma vez
        await asyncio.sleep(1)  # pausa entre itens do lote


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

O que vale para qualquer biblioteca#

  • Respeite Retry-After. Não repita antes do tempo. Se você faz requisições HTTP à mão, leia o header e espere.
  • Processe lotes com intervalo. Uma fila com pausa entre itens custa segundos e evita o problema.
  • Edite menos. Atualize um painel a cada 10 ou 30 segundos, não a cada segundo.
  • Use o endpoint em lote quando existir. Apagar muitas mensagens tem endpoint próprio (bulk delete), em vez de uma chamada por mensagem.
  • Não repita 401 e 403. Token inválido ou falta de permissão não se resolvem tentando de novo. Corrija a causa.

O que é o ban temporário do Cloudflare?#

Se o seu IP passa de 10.000 requisições inválidas em 10 minutos, o Discord bloqueia temporariamente esse IP na API. Isso dá cerca de 16 a 17 inválidas por segundo, sem parar. Acontece em loops de reinício e em retry sem pausa, não em uso normal.

Se você suspeita de bloqueio:

  1. Pare o bot. Cada tentativa nova só alimenta o contador.
  2. Descubra o que gerava as respostas 401, 403 e 429. Os logs mostram a rota.
  3. Corrija o loop e espere o bloqueio expirar.
  4. Suba o bot de novo com invalidRequestWarningInterval ligado, como no exemplo acima.

Como saber se é rate limit ou outro problema?#

  • 429 com retry_after pequeno: rate limit comum, a biblioteca resolve.
  • 429 com global: true repetido: você passou de 50 requisições por segundo. Procure o loop.
  • 401 repetido: token errado ou redefinido.
  • 403 repetido: o bot não tem permissão naquele canal ou cargo. Confira antes de chamar.
  • Todas as chamadas falham de uma vez: possível bloqueio de IP.
  • Bot cai e reinicia sem parar: veja por que o bot fica offline.

Como fazer isso na Square Cloud#

O rate limit é uma regra da API do Discord e vale em qualquer hospedagem. O que muda de uma hospedagem para outra é a rapidez com que você enxerga o problema. Na Square Cloud, os logs ficam disponíveis em tempo real no painel, na CLI e no VS Code, então um aviso de requisições inválidas aparece enquanto o bot roda.

O reinício automático, opcional e ligado por padrão no deploy pelo painel, traz o bot de volta quando o processo encerra com erro. Isso mantém o bot no ar, mas com um token inválido cada reinício pode gerar mais uma resposta 401, como no loop descrito acima. Por isso, trate o erro de login no código: registre uma mensagem clara no log, não repita a tentativa e corrija o token nas variáveis de ambiente antes de reiniciar.

Bots de Discord rodam em containers isolados, com discord.js, discord.py, JDA, Discord.Net ou outra biblioteca de Gateway, e a latência média até o Gateway do Discord é de cerca de 30 ms. O deploy é por upload de ZIP, CLI, GitHub ou extensão do VS Code, e o token fica nas variáveis de ambiente da aplicação. Veja os detalhes em hospedagem de bots de Discord. Para subir o primeiro bot, siga o guia de como hospedar um bot do discord.js.

Hospedagem de bots

Seu bot online 24/7, com reinício automático

Saiba mais

Perguntas frequentes

Quanto tempo dura um erro 429 no Discord?

O tempo vem na própria resposta, no header Retry-After e no campo retry_after do JSON, em segundos. Esperar esse tempo e tentar de novo resolve.

Qual é o limite global de requisições do Discord?

Cada bot pode fazer até 50 requisições por segundo à API REST. Além disso, cada rota tem o próprio limite, que você descobre pelos headers X-RateLimit-*.

Posso ser banido por causa de erros 429?

Sim. Respostas 401, 403 e 429 contam como requisições inválidas, e 10.000 delas em 10 minutos fazem o Discord bloquear temporariamente o IP. Um 429 com X-RateLimit-Scope shared não conta.

O discord.js e o discord.py tratam o 429 sozinhos?

Sim, ambos esperam o rate limit por padrão. O problema aparece quando o código gera volume demais, repete requisições que falham ou reinicia em loop com um token inválido.

Próximo artigoComo hospedar um bot do Discord em Node.js (discord.js)Para hospedar um bot discord.js, crie o app no Portal, guarde o token em variável de ambiente e rode o processo numa máquina sempre ligada. Veja o passo a passo.