Bot online mas não responde aos comandos: causas comuns

Um bot online que não responde costuma estar sem a intent Message Content, sem comandos registrados ou sem permissão no canal. Confira o log e a página Bot do Developer Portal.

Atualizado em 5 min de leitura

Objetivos de aprendizado

Depois de ler este artigo, você vai conseguir:

  • Separar bot de prefixo (mensagens) de bot de slash commands (interações)
  • Diagnosticar intent, registro de comandos, permissões e o prazo de 3 segundos
  • Corrigir cada causa com código atual do discord.js v14
Nesta página

O bot está com a bolinha verde, mas você digita o comando e nada acontece. Isso é diferente de um bot offline: aqui a conexão com o Gateway existe, e o problema está no que o bot recebe, no que ele pode fazer ou no tempo que leva para responder.

A primeira pergunta decide todo o diagnóstico: o seu comando é uma mensagem com prefixo (!ping) ou um slash command (/ping)? Os dois caminhos usam eventos diferentes e quebram por motivos diferentes.

Online, mas mudoPrefixo!pingSlash/pingIntentMessage Contentsem ela, o content vem vazioligue no Portal e no código1Comando registradopela API HTTP (PUT)2Escopo do conviteapplications.commands3Resposta em até 3 sou deferReply() antesNos dois: permissão no canal (50013, 50001)
Prefixo depende da intent Message Content; slash depende de registro, escopo e resposta em 3 s. Permissão vale para os dois.

Como saber se o bot recebe o evento?#

Antes de suspeitar de intent ou permissão, prove que o evento chega. Um console.log na primeira linha do handler separa "o bot nem recebe" de "recebe e falha depois".

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

const client = new Client({
  intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
});

client.on(Events.MessageCreate, (m) => console.log("msg:", JSON.stringify(m.content)));
client.on(Events.InteractionCreate, (i) => console.log("interaction:", i.type, i.commandName));

client.login(process.env.DISCORD_TOKEN);

Se msg: aparece com "" (vazio) para mensagens que têm texto, a causa é a intent de conteúdo. Se nada aparece para o slash command, o problema é registro ou escopo. Se aparece e o usuário não vê resposta, o problema é permissão, erro no handler ou tempo.

Por que o bot de prefixo ignora as mensagens?#

É a causa mais comum. Sem a intent privilegiada Message Content (valor 1 << 15, 32768), o Discord entrega os campos content, embeds, attachments, components e poll vazios. As exceções são mensagens do próprio bot, DMs com o bot, mensagens que mencionam o bot e a mensagem alvo de um comando de menu de contexto.

Por isso message.content.startsWith("!") nunca é verdadeiro: o bot recebe o evento, mas o texto não vem. Corrija em dois lugares:

  1. No Developer Portal, página Bot, ligue Message Content Intent. Apps não verificados ligam direto. A verificação é obrigatória a partir de 100 servidores, e aí a intent também precisa ser aprovada.
  2. No código, declare a intent:
js
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

Se você declara a intent no código sem ligá-la no portal, o Gateway fecha a conexão com o código 4014 (o bot fica offline, não mudo). Mais detalhes em erro de intents no bot do Discord. Se o bot só precisa de comandos, migrar para slash commands elimina a dependência dessa intent.

Por que o slash command não aparece ou não faz nada?#

Um slash command não passa a existir só porque o bot está rodando. Ele precisa ser registrado pela API HTTP: PUT /applications/{id}/commands para global, PUT /applications/{id}/guilds/{guild_id}/commands para um servidor. Se você só escreveu o handler, o Discord não conhece o comando.

Confira:

  • Registrou? Comandos de servidor atualizam na hora, então use-os para testar. Comandos globais servem para produção.
  • Convidou com o escopo certo? Criar comandos em um servidor exige o escopo applications.commands. O escopo bot já o inclui, mas um convite feito só com outros escopos não.
  • É o servidor certo? Um comando registrado em um servidor não existe nos outros nem em DMs.
  • Limites: são 100 comandos CHAT_INPUT globais e 200 criações de comando por dia, por servidor. Em vez de recriar um a um, use o bulk overwrite (PUT), que substitui a lista inteira (comandos omitidos são removidos).

Por que aparece "O aplicativo não respondeu"?#

O Discord exige uma resposta inicial à interação em até 3 segundos. Passou disso, o token é invalidado e o usuário vê a falha. O mesmo acontece se o handler lança uma exceção antes de responder. Consultar banco, chamar API externa ou gerar imagem costuma estourar esse prazo.

A solução é reconhecer a interação primeiro e responder depois:

js
import { MessageFlags } from "discord.js";

client.on(Events.InteractionCreate, async (interaction) => {
  if (!interaction.isChatInputCommand()) return;
  if (interaction.commandName !== "relatorio") return;

  try {
    await interaction.deferReply(); // responde em menos de 3 s, usuário vê "pensando..."
    const texto = await gerarRelatorio(); // pode demorar
    await interaction.editReply(texto); // o token vale por 15 minutos
  } catch (err) {
    console.error(err);
    if (interaction.deferred || interaction.replied) {
      await interaction.editReply("Algo deu errado.");
    } else {
      await interaction.reply({ content: "Algo deu errado.", flags: MessageFlags.Ephemeral });
    }
  }
});

O token da interação vale 15 minutos para editReply e followUp. Dois erros relacionados aparecem no log: 10062 Unknown interaction (a interação expirou) e 40060 Interaction has already been acknowledged (você respondeu duas vezes; troque o segundo reply por followUp ou editReply).

O bot tem permissão para responder naquele canal?#

Se o evento chega e o código roda sem erro, mas nada aparece, o bot pode não ter permissão de enviar. No log você vê:

text
DiscordAPIError[50013]: Missing Permissions
DiscordAPIError[50001]: Missing Access

50013 é falta de permissão para a ação (por exemplo, Send Messages ou Embed Links) e 50001 é falta de acesso ao canal (View Channel). A causa costuma ser um override de permissão no canal ou na categoria que sobrepõe o cargo do bot. Teste com o cargo do bot em Administrador num servidor de teste: se passar a funcionar, o problema é permissão, e você ajusta o mínimo necessário. Não deixe Administrador em produção.

E se o handler falhar em silêncio?#

Em código async, uma exceção sem try/catch vira uma promessa rejeitada sem tratamento. Nas versões atuais do Node.js isso derruba o processo por padrão, e se algum wrapper engolir a rejeição, o erro nem aparece. Adicione process.on("unhandledRejection", console.error) e trate erros no handler, como no exemplo acima. Confira também o rate limit: um loop que envia mensagens demais recebe 429 e fica mudo por alguns segundos, caso explicado em erro 429 no Discord.

Por fim, mudanças de código só valem depois de reiniciar o processo. Se você editou o handler e nada mudou, confirme que a versão nova é a que está rodando.

Como fazer isso na Square Cloud#

Para diagnosticar um bot mudo, o que você mais precisa é do log em tempo real. Na Square Cloud ele aparece no painel, na CLI, na extensão do VS Code e no app de celular, então dá para colocar os console.log acima, reiniciar e ver o resultado na hora.

O token fica nas variáveis de ambiente da aplicação (painel, API, CLI ou VS Code), e a mudança vale no próximo restart, sem rebuild. A hospedagem aceita discord.js, discord.py, JDA, Discord.Net ou qualquer biblioteca de Gateway. Cada aplicação de fundo, como um bot, reserva no mínimo 256 MB do pool de RAM do plano.

Veja a página de hospedagem de bots do Discord para os detalhes e os planos.

Hospedagem de bots

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

Saiba mais

Perguntas frequentes

Por que meu bot aparece online mas não responde a !comandos?

O conteúdo das mensagens é uma intent privilegiada. Sem a Message Content ligada no Developer Portal e declarada no código, o campo content chega vazio e o seu prefixo nunca casa.

O que significa 'O aplicativo não respondeu' num slash command?

O Discord exige uma resposta inicial em até 3 segundos. Se o handler demora mais, ou lança erro antes de responder, o usuário vê essa falha. Use deferReply() para ganhar tempo.

Meu slash command novo não aparece na lista. O que fazer?

Comandos só existem depois de registrados pela API (PUT em /applications/{id}/commands). Registre como comando de servidor para testar, porque eles atualizam na hora, e confirme que o bot foi convidado com o escopo applications.commands.

O bot responde no meu servidor de teste mas não em outros. Por quê?

Normalmente é permissão: o bot precisa de View Channel e Send Messages no canal, e um cargo ou override pode negar isso. Também vale checar se o comando foi registrado só nesse servidor.

Próximo artigoToken do bot do Discord: onde pegar e como guardarO token do bot do Discord fica na aba Bot do Portal de Desenvolvedores e funciona como a senha do bot. Veja onde pegar, como guardar e o que fazer se vazar.