Bot de Discord en línea que no responde a los comandos

Un bot en línea que no responde suele estar sin la intent Message Content, sin comandos registrados o sin permisos en el canal. Revisa el log y la página Bot del Developer Portal.

Actualizado el 5 min de lectura

Objetivos de aprendizaje

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

  • Distinguir un bot de prefijo (mensajes) de un bot de slash commands (interacciones)
  • Diagnosticar intents, registro de comandos, permisos y el plazo de 3 segundos
  • Corregir cada causa con código actual de discord.js v14
En esta página

El bot tiene el punto verde, pero escribes el comando y no pasa nada. Eso es distinto de un bot desconectado: aquí la conexión con el Gateway existe, y el problema está en lo que el bot recibe, en lo que tiene permitido hacer o en lo que tarda en responder.

Una pregunta decide todo el diagnóstico: ¿tu comando es un mensaje con prefijo (!ping) o un slash command (/ping)? Los dos usan eventos distintos y fallan por motivos distintos.

En línea, pero mudoPrefijo!pingSlash/pingIntentMessage Contentsin ella, content llega vacíoen el Portal y en el código1Comando registradopor la API HTTP (PUT)2Scope al invitarapplications.commands3Respuesta en 3 so deferReply() antesEn ambos: permiso en el canal (50013, 50001)
El prefijo depende de la intent Message Content; el slash, del registro, el scope y responder en 3 s. El permiso vale para ambos.

¿Cómo saber si el bot recibe el evento?#

Antes de sospechar de intents o permisos, demuestra que el evento llega. Un console.log en la primera línea del handler separa "el bot ni lo recibe" de "lo recibe y falla después".

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);

Si msg: aparece con "" (vacío) en mensajes que sí tienen texto, la causa es la intent de contenido. Si no aparece nada con el slash command, el problema es el registro o el scope. Si aparece y el usuario no ve respuesta, el problema es de permisos, un error en el handler o el tiempo.

¿Por qué el bot de prefijo ignora los mensajes?#

Es la causa más común. Sin la intent privilegiada Message Content (valor 1 << 15, 32768), Discord entrega vacíos los campos content, embeds, attachments, components y poll. Las excepciones son los mensajes del propio bot, los MD con el bot, los mensajes que mencionan al bot y el mensaje objetivo de un comando de menú contextual.

Por eso message.content.startsWith("!") nunca es verdadero: el bot recibe el evento, pero el texto no llega. Corrígelo en dos lugares:

  1. En el Developer Portal, página Bot, activa Message Content Intent. Las apps sin verificar la activan directamente. La verificación es obligatoria a partir de 100 servidores, y entonces la intent también tiene que ser aprobada.
  2. En el código, declara la intent:
js
const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

Si declaras la intent en el código sin activarla en el portal, el Gateway cierra la conexión con el código 4014 (el bot queda desconectado, no mudo). Más detalles en error de intents en el bot de Discord. Si el bot solo necesita comandos, migrar a slash commands elimina la dependencia de esa intent.

¿Por qué el slash command no aparece o no hace nada?#

Un slash command no existe solo porque el bot esté en ejecución. Tiene que registrarse por la API HTTP: PUT /applications/{id}/commands para los globales, PUT /applications/{id}/guilds/{guild_id}/commands para un servidor. Si solo escribiste el handler, Discord no conoce el comando.

Revisa:

  • ¿Lo registraste? Los comandos de servidor se actualizan al instante, así que úsalos para probar. Los globales son para producción.
  • ¿Invitaste al bot con el scope correcto? Crear comandos en un servidor exige el scope applications.commands. El scope bot ya lo incluye, pero una invitación hecha solo con otros scopes no.
  • ¿Es el servidor correcto? Un comando registrado en un servidor no existe en los demás ni en los MD.
  • Límites: son 100 comandos CHAT_INPUT globales y 200 creaciones de comandos por día, por servidor. En lugar de recrearlos uno a uno, usa el bulk overwrite (PUT), que reemplaza la lista entera (los comandos omitidos se eliminan).

¿Por qué aparece "La aplicación no ha respondido"?#

Discord exige una respuesta inicial a la interacción en un máximo de 3 segundos. Pasado ese plazo, el token se invalida y el usuario ve el fallo. Lo mismo ocurre si el handler lanza una excepción antes de responder. Consultar una base de datos, llamar a una API externa o generar una imagen suele superar ese plazo.

La solución es confirmar la interacción primero y responder después:

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

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

  try {
    await interaction.deferReply(); // responde en menos de 3 s, el usuario ve "pensando..."
    const texto = await generarInforme(); // puede tardar
    await interaction.editReply(texto); // el token vale 15 minutos
  } catch (err) {
    console.error(err);
    if (interaction.deferred || interaction.replied) {
      await interaction.editReply("Algo salió mal.");
    } else {
      await interaction.reply({ content: "Algo salió mal.", flags: MessageFlags.Ephemeral });
    }
  }
});

El token de la interacción vale 15 minutos para editReply y followUp. Dos errores relacionados aparecen en el log: 10062 Unknown interaction (la interacción expiró) y 40060 Interaction has already been acknowledged (respondiste dos veces; cambia el segundo reply por followUp o editReply).

¿El bot tiene permiso para responder en ese canal?#

Si el evento llega y el código se ejecuta sin errores, pero no aparece nada, puede que el bot no tenga permiso para enviar. En el log ves:

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

50013 es falta de permiso para la acción (por ejemplo, Send Messages o Embed Links) y 50001 es falta de acceso al canal (View Channel). La causa suele ser un override de permisos en el canal o en la categoría que se impone al rol del bot. Prueba dándole Administrador al rol del bot en un servidor de prueba: si empieza a funcionar, el problema son los permisos, y ajustas lo mínimo necesario. No dejes Administrador en producción.

¿Y si el handler falla en silencio?#

En código async, una excepción sin try/catch se convierte en una promesa rechazada sin manejar. En las versiones actuales de Node.js eso tumba el proceso por defecto, y si algún wrapper se traga el rechazo, el error ni siquiera aparece. Añade process.on("unhandledRejection", console.error) y maneja los errores en el handler, como en el ejemplo de arriba. Revisa también el rate limit: un bucle que envía demasiados mensajes recibe 429 y queda mudo unos segundos, caso explicado en error 429 en Discord.

Por último, los cambios de código solo valen después de reiniciar el proceso. Si editaste el handler y nada cambió, confirma que la versión nueva es la que se está ejecutando.

Cómo hacerlo en Square Cloud#

Para diagnosticar un bot mudo, lo que más necesitas es el log en tiempo real. En Square Cloud aparece en el panel, la CLI, la extensión de VS Code y la app móvil, así que puedes añadir los console.log de arriba, reiniciar y ver el resultado al momento.

El token va en las variables de entorno de la aplicación (panel, API, CLI o VS Code), y el cambio se aplica en el siguiente reinicio, sin rebuild. El hosting acepta discord.js, discord.py, JDA, Discord.Net o cualquier biblioteca de Gateway. Cada aplicación en segundo plano, como un bot, reserva como mínimo 256 MB del pool de RAM del plan.

Consulta la página de hosting de bots de Discord para ver los detalles y los planes.

Hosting de bots

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

Más información

Preguntas frecuentes

¿Por qué mi bot está en línea pero no responde a los !comandos?

El contenido de los mensajes es una intent privilegiada. Sin Message Content activada en el Developer Portal y declarada en el código, el campo content llega vacío y tu prefijo nunca coincide.

¿Qué significa 'La aplicación no ha respondido' en un slash command?

Discord exige una respuesta inicial en un máximo de 3 segundos. Si tu handler tarda más, o lanza un error antes de responder, el usuario ve ese fallo. Usa deferReply() para ganar tiempo.

Mi nuevo slash command no aparece en la lista. ¿Qué hago?

Los comandos solo existen después de registrarlos por la API (PUT en /applications/{id}/commands). Regístralos como comandos de servidor para probar, porque se actualizan al instante, y confirma que invitaste al bot con el scope applications.commands.

El bot responde en mi servidor de prueba pero no en otros. ¿Por qué?

Normalmente son permisos: el bot necesita View Channel y Send Messages en el canal, y un rol o un override puede negarlos. También conviene comprobar si el comando se registró solo en ese servidor.

Siguiente artículoToken del bot de Discord: dónde encontrarlo y cómo protegerloEl token del bot de Discord está en la pestaña Bot del Portal de Desarrolladores y es la contraseña del bot. Dónde obtenerlo, guardarlo y qué hacer si se filtra.