Objetivos de aprendizaje
Después de leer este artículo podrás:
- Identificar con el código de desconexión por qué se cayó la sesión
- Corregir las causas comunes: carpeta de sesión perdida, dos instancias y dispositivo eliminado
- Armar una reconexión que no entre en bucle ni borre la sesión sin querer
En esta página
- ¿Qué significa que el bot pida el QR otra vez?
- ¿Cómo leer el motivo de la desconexión en Baileys?
- ¿Por qué la sesión desaparece en cada reinicio?
- ¿Cómo saber si dos instancias se disputan la sesión?
- ¿El teléfono eliminó el dispositivo o quedó inactivo?
- ¿Y en whatsapp-web.js?
- ¿Cómo evitar que la sesión se caiga de nuevo?
- Cómo hacerlo en Square Cloud
- Preguntas frecuentes
Tu bot de WhatsApp funcionaba y, de pronto, el log muestra la conexión cerrada o la terminal vuelve a pedir un código QR. Lo escaneas, funciona unas horas o hasta el siguiente reinicio, y el ciclo se repite. Casi siempre el problema no es la biblioteca: es la sesión, es decir, las credenciales que le demuestran a WhatsApp que ese dispositivo vinculado eres tú.
Los ejemplos cubren Baileys y whatsapp-web.js, las dos bibliotecas no oficiales más usadas, con la versión LTS activa de Node.js y la API de Baileys 7. Si aún no tienes un bot funcionando, empieza por cómo hacer un bot de WhatsApp.
¿Qué significa que el bot pida el QR otra vez?#
Un bot no oficial se conecta como un dispositivo vinculado, igual que WhatsApp Web. En el primer emparejamiento, WhatsApp entrega credenciales y la biblioteca las guarda en disco. En las siguientes ejecuciones las lee y conecta sin QR.
Que pida el QR otra vez significa que, al conectar, no había una sesión válida. Solo hay dos motivos: la sesión no estaba (carpeta borrada, otra ruta) o WhatsApp la invalidó (dispositivo eliminado, sesión reemplazada). Distinguir cuál de los dos es todo el diagnóstico.
¿Cómo leer el motivo de la desconexión en Baileys?#
El evento connection.update trae lastDisconnect.error.output.statusCode cuando la conexión se cierra. Estos son los códigos del enum DisconnectReason de Baileys:
| Código | Nombre | Significado | Qué hacer |
|---|---|---|---|
| 401 | loggedOut |
WhatsApp cerró la sesión de este dispositivo | Borrar la carpeta y vincular de nuevo |
| 440 | connectionReplaced |
Otra conexión tomó la misma sesión | Encontrar y apagar la otra instancia |
| 500 | badSession |
Credenciales corruptas o incompletas | Borrar la carpeta y vincular de nuevo |
| 515 | restartRequired |
WhatsApp pidió reiniciar el socket | Reconectar |
| 428 / 408 | connectionClosed / connectionLost |
Caída de red o timeout | Reconectar con espera |
En lugar de reconectar a ciegas, registra el código y trata cada caso. El ejemplo reconecta con una espera creciente y solo se rinde en los códigos donde reintentar no ayuda. Define WA_PHONE con el número del bot (solo dígitos, con código de país) y AUTH_DIR con la carpeta de la sesión:
import makeWASocket, {
DisconnectReason,
useMultiFileAuthState,
} from "baileys";
const AUTH_DIR = process.env.AUTH_DIR ?? "auth_info";
const PHONE = process.env.WA_PHONE;
let intentos = 0;
async function start() {
const { state, saveCreds } = await useMultiFileAuthState(AUTH_DIR);
const sock = makeWASocket({ auth: state });
let codeRequested = false;
sock.ev.on("creds.update", saveCreds);
sock.ev.on("connection.update", async ({ connection, lastDisconnect, qr }) => {
if (qr && !codeRequested && !sock.authState.creds.registered) {
if (!PHONE) return console.error("Define WA_PHONE para vincular.");
codeRequested = true; // el qr se renueva; pide el código una vez por conexión
console.log("Código de vinculación:", await sock.requestPairingCode(PHONE));
}
if (connection === "open") {
intentos = 0;
console.log("Conectado a WhatsApp.");
}
if (connection === "close") {
const code = lastDisconnect?.error?.output?.statusCode;
console.error("Conexión cerrada. Código:", code);
if (code === DisconnectReason.loggedOut || code === DisconnectReason.badSession) {
console.error(`Sesión inválida. Borra la carpeta ${AUTH_DIR} y vincula de nuevo.`);
process.exit(0); // sale sin error: quien reinicia en error no entra en bucle
}
if (code === DisconnectReason.connectionReplaced) {
console.error("Otra instancia usa esta sesión. Saliendo.");
process.exit(0);
}
const espera = Math.min(30_000, 1_000 * 2 ** intentos++);
setTimeout(start, espera);
}
});
}
start();El código no borra la carpeta por sí solo, y es a propósito: borrar la sesión por error es la forma más rápida de convertir una caída de red en un nuevo emparejamiento. Decides tú, leyendo el log.
En los casos sin salida (401, 500 y 440), el proceso termina con código 0, sin error. Un supervisor que reinicia el bot cuando sale con error, como el reinicio automático de un hosting, lo volvería a levantar y crearía un bucle: en el 401 y el 500, con la misma sesión inválida; en el 440, expulsando a la otra instancia.
¿Por qué la sesión desaparece en cada reinicio?#
Es la causa más común. La carpeta de autenticación debe estar en un disco que sobreviva al reinicio del proceso. Desaparece cuando:
- El bot corre en una plataforma con disco efímero, que recrea el sistema de archivos en cada deploy o reinicio. La documentación de whatsapp-web.js advierte que
LocalAuthnecesita un sistema de archivos persistente y no sirve para hosts efímeros como Heroku. - La ruta cambia: usas una ruta relativa y ejecutas el bot desde carpetas distintas.
- Vuelves a subir el proyecto completo (ZIP o git) y la carpeta de sesión se sobrescribe o se elimina sin que lo notes.
Para comprobarlo, ejecuta el bot, vincula, detén el proceso y ejecútalo de nuevo. Si vuelve a pedir QR o código, la carpeta no se está leyendo. Lista el contenido de AUTH_DIR antes y después del reinicio: debe haber un creds.json y varios archivos de claves.
En producción, la documentación de Baileys recomienda guardar el estado de autenticación en una base de datos y no en archivos, y presenta useMultiFileAuthState como guía para escribir ese almacenamiento. Si pierdes la carpeta con frecuencia, una base de datos es el camino. La guía de bot de WhatsApp 24/7 muestra lo básico de la sesión en disco.
¿Cómo saber si dos instancias se disputan la sesión?#
El síntoma es el código 440 (connectionReplaced) y un bot que se cae cada pocos segundos. Cuando una segunda conexión usa las mismas credenciales, la anterior es expulsada. Si cada instancia reconecta sola, se expulsan una a otra sin fin.
Los sospechosos de siempre:
- Dejaste el bot corriendo en tu PC y subiste el mismo a un servidor.
- El deploy nuevo arranca antes de que muera el proceso viejo.
- Un supervisor de procesos como PM2, o una política
restart: always, mantiene viva una copia que no ves. - Copiaste la carpeta de sesión a otro lugar y ejecutaste las dos.
La solución es garantizar una sola instancia por sesión. Si necesitas probar en local, vincula un segundo número de prueba en lugar de reutilizar la carpeta de producción.
¿El teléfono eliminó el dispositivo o quedó inactivo?#
El código 401 (loggedOut) significa que WhatsApp cerró ese dispositivo vinculado. Dos causas:
- Alguien eliminó el dispositivo en Ajustes, Dispositivos vinculados, o cerró sesión en la cuenta desde el teléfono.
- El teléfono principal estuvo más de 14 días sin usarse. Según el Centro de Ayuda de WhatsApp, el teléfono no necesita estar en línea para que los dispositivos vinculados funcionen, pero se desconectan si no usas el teléfono durante más de 14 días.
El límite de dispositivos también cuenta: el Centro de Ayuda indica cuántos dispositivos puedes vincular a una cuenta. Si ya usas WhatsApp Web, la app de escritorio y otros bots en el mismo número, revisa la lista en Dispositivos vinculados y quita lo que no uses.
En ambos casos, la única salida es borrar la carpeta de sesión y vincular de nuevo. Reconectar con las credenciales viejas solo repite el 401.
¿Y en whatsapp-web.js?#
whatsapp-web.js guarda la sesión con LocalAuth, que por defecto almacena los datos del navegador en la carpeta .wwebjs_auth. Sin authStrategy, el cliente no persiste nada y pide QR en cada ejecución:
const { Client, LocalAuth } = require("whatsapp-web.js");
const qrcode = require("qrcode-terminal");
const client = new Client({
authStrategy: new LocalAuth({
clientId: "bot-principal",
dataPath: process.env.AUTH_DIR ?? ".wwebjs_auth",
}),
});
client.on("qr", (qr) => qrcode.generate(qr, { small: true }));
client.on("ready", () => console.log("Conectado a WhatsApp."));
client.on("disconnected", (reason) => {
// reason es "LOGOUT" o un estado de WhatsApp Web, como CONFLICT o UNPAIRED
console.error("Desconectado:", reason);
});
client.initialize();El evento disconnected recibe "LOGOUT" cuando la sesión se cerró, o un estado como CONFLICT (otra sesión tomó el control, el equivalente al 440) o UNPAIRED (el dispositivo se desvinculó). Las causas son las mismas que en Baileys: carpeta perdida, dos instancias, dispositivo eliminado. Y suma una propia: como un Chromium corre junto al bot, quedarse sin memoria puede tumbar el navegador y llevarse la conexión. Si el proceso muere sin un mensaje claro, revisa primero el consumo de RAM.
¿Cómo evitar que la sesión se caiga de nuevo?#
- Una sesión, una instancia. Nunca ejecutes la misma carpeta en dos lugares.
- Carpeta persistente y fuera del código. Define
AUTH_DIRcon una variable de entorno y mantenla fuera del repositorio. - Registra el código de cada desconexión. Sin el log, adivinas. Con él, el diagnóstico toma un minuto.
- Reconecta con espera, no en bucle. Reintentos inmediatos e infinitos solo llenan el log y esconden la causa.
- Usa el teléfono principal de vez en cuando. Abre WhatsApp en él al menos cada dos semanas.
- No trates un bot no oficial como garantizado. Las bibliotecas no oficiales pueden romperse cuando WhatsApp cambia el protocolo, y usarlas contra los Términos de Servicio es riesgo tuyo. Para uso comercial, compara con la Cloud API oficial en Baileys, whatsapp-web.js o Cloud API: usa webhook y token, sin depender de la sesión de un dispositivo vinculado.
Cómo hacerlo en Square Cloud#
Square Cloud es hosting self-service: tú subes el bot, eliges la memoria y controlas el código. Puedes alojar bots de WhatsApp hechos con Baileys, WPPConnect, whatsapp-web.js o la Cloud API oficial. La carpeta de autenticación queda en el disco de la aplicación, que persiste entre reinicios y deploys, así que la sesión sigue conectada. Un nuevo ZIP sobrescribe solo los archivos que contiene: deja la carpeta de autenticación fuera del ZIP para no reemplazarla.
Eso elimina la causa más común del QR repetido: la sesión que desaparece en cada reinicio. Los contenedores están siempre encendidos, y el reinicio automático, que viene activado en el deploy desde el panel, vuelve a levantar el proceso cuando termina con error. Por eso el ejemplo sale con código 0 cuando la sesión es inválida. Puedes seguir los códigos de desconexión en los logs en tiempo real del panel o de la CLI. Cada aplicación en segundo plano, como un bot, tiene como mínimo 256 MB de RAM; si usas whatsapp-web.js con Chromium, reserva más memoria.
Define AUTH_DIR y WA_PHONE en las variables de entorno de la aplicación. La regla de una instancia por sesión sigue valiendo: al subir el bot, apaga el que corre en tu PC. Consulta los detalles en hosting de bots de WhatsApp en Square Cloud.
Hosting de bots
Tu bot en línea 24/7, con reinicio automático
Preguntas frecuentes
¿Por qué mi bot de WhatsApp pide el QR cada vez que se reinicia?
Porque la carpeta de autenticación no sobrevive al reinicio. Pasa con discos efímeros, con redeploys que recrean el contenedor o cuando el código apunta a una carpeta distinta en cada ejecución. Guarda la sesión en una ruta persistente.
¿Qué significa el error 401 loggedOut en Baileys?
WhatsApp cerró la sesión de este dispositivo vinculado. Suele ser porque alguien lo quitó en Dispositivos vinculados o porque el teléfono principal estuvo más de 14 días sin usarse. Reconectar con las mismas credenciales no sirve: hay que borrar la carpeta y vincular de nuevo.
¿Puedo correr el mismo bot en mi PC y en un servidor a la vez?
No con la misma sesión. La segunda conexión expulsa a la primera con el código 440 (connectionReplaced), y si cada una reconecta sola se expulsan entre sí. Usa una sesión por instancia.
¿El bot de WhatsApp necesita que mi teléfono esté encendido?
Los dispositivos vinculados funcionan sin que el teléfono esté en línea, pero se desconectan si el teléfono principal pasa más de 14 días sin usarse. Abrir WhatsApp en el teléfono de vez en cuando basta.
Más en Bots
Ver los 33 artículos- ¿Cuánto cuesta hospedar un bot de Discord?El costo de hospedar un bot de Discord depende de la RAM, el tiempo en línea, la base de datos y los servicios externos. Aprende a estimar el tuyo.
- Correr un bot en el celular (Termux) o en tu PC vs hospedarloUn bot en tu PC o celular (Termux) se cae cuando el equipo se apaga, se suspende o pierde la red. Compara las tres opciones y cuándo sirve cada una.
- Cómo mantener tu bot de Discord en línea 24/7Para mantener un bot de Discord en línea 24/7, ejecuta el proceso en una máquina siempre encendida con reinicio automático. Compara PC, VPS con pm2 o systemd.
- Por qué tu bot de Discord se apaga o aparece offlineUn bot de Discord aparece offline cuando el proceso se cae, el token es inválido, falta una intent o se acaba la memoria. Diagnostica y corrige cada causa.