Bot de WhatsApp desconectando ou pedindo QR code de novo

Um bot de WhatsApp pede QR code de novo quando perde a sessão: o aparelho foi removido, a pasta de autenticação sumiu ou duas instâncias disputam a sessão. O código de desconexão mostra qual.

Atualizado em 7 min de leitura

Objetivos de aprendizado

Depois de ler este artigo, você vai conseguir:

  • Identificar pelo código de desconexão por que a sessão caiu
  • Corrigir as causas mais comuns: pasta de sessão perdida, duas instâncias e aparelho removido
  • Montar uma reconexão que não entra em loop nem apaga a sessão sem querer
Nesta página

Seu bot de WhatsApp funcionava, e de repente o log mostra a conexão fechada ou o terminal volta a pedir um QR code. Você escaneia, ele funciona por algumas horas ou até o próximo restart, e o ciclo recomeça. Quase sempre o problema não é a biblioteca: é a sessão, ou seja, as credenciais que provam ao WhatsApp que aquele aparelho vinculado é você.

Os exemplos cobrem Baileys e whatsapp-web.js, as duas bibliotecas não oficiais mais usadas, com a versão LTS ativa do Node.js e a API do Baileys 7. Se ainda não tem um bot rodando, comece por como fazer um bot de WhatsApp.

Conexão fechadaconnection.updatestatusCode401loggedOutApague a sessão,pareie de novo440connectionReplacedDesligue a outrainstânciaoutros515, 428, 408Reconectecom esperaespera 1s, 2s, 4s…
Os outros códigos reconectam com espera; 401 e 440 param o bot, porque reconectar com a mesma sessão não adianta.

O que significa o bot pedir QR code de novo?#

Um bot não oficial se conecta como um aparelho vinculado, igual ao WhatsApp Web. No primeiro pareamento, o WhatsApp entrega credenciais que a biblioteca grava em disco. Nas execuções seguintes, ela lê essas credenciais e conecta sem QR.

Pedir QR de novo significa que, na hora de conectar, não havia sessão válida. Só existem dois motivos: a sessão não estava lá (pasta apagada, outro caminho) ou o WhatsApp a invalidou (aparelho removido, sessão substituída). Descobrir qual dos dois é o diagnóstico inteiro.

Como ler o motivo da desconexão no Baileys?#

O evento connection.update traz lastDisconnect.error.output.statusCode quando a conexão fecha. Estes são os códigos do enum DisconnectReason do Baileys:

Código Nome Significado O que fazer
401 loggedOut O WhatsApp encerrou a sessão deste aparelho Apagar a pasta e parear de novo
440 connectionReplaced Outra conexão assumiu a mesma sessão Achar e desligar a outra instância
500 badSession Credenciais corrompidas ou incompletas Apagar a pasta e parear de novo
515 restartRequired O WhatsApp pediu para reiniciar o socket Reconectar
428 / 408 connectionClosed / connectionLost Queda de rede ou timeout Reconectar com espera

Em vez de reconectar às cegas, registre o código e trate cada caso. O exemplo abaixo reconecta com espera crescente e só desiste nos códigos em que repetir não adianta. Defina WA_PHONE com o número do bot, só dígitos e com código do país, e AUTH_DIR com a pasta da sessão:

js
import makeWASocket, {
  DisconnectReason,
  useMultiFileAuthState,
} from "baileys";

const AUTH_DIR = process.env.AUTH_DIR ?? "auth_info";
const PHONE = process.env.WA_PHONE;
let tentativas = 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("Defina WA_PHONE para parear.");
      codeRequested = true; // o qr se renova; peça o código uma vez por conexão
      console.log("Código de pareamento:", await sock.requestPairingCode(PHONE));
    }

    if (connection === "open") {
      tentativas = 0;
      console.log("Conectado ao WhatsApp.");
    }

    if (connection === "close") {
      const code = lastDisconnect?.error?.output?.statusCode;
      console.error("Conexão fechada. Código:", code);

      if (code === DisconnectReason.loggedOut || code === DisconnectReason.badSession) {
        console.error(`Sessão inválida. Apague a pasta ${AUTH_DIR} e pareie de novo.`);
        process.exit(0); // sai sem erro: quem reinicia em erro não entra em loop
      }
      if (code === DisconnectReason.connectionReplaced) {
        console.error("Outra instância usa esta sessão. Encerrando.");
        process.exit(0);
      }

      const espera = Math.min(30_000, 1_000 * 2 ** tentativas++);
      setTimeout(start, espera);
    }
  });
}

start();

O código não apaga a pasta sozinho, e isso é proposital: apagar a sessão por engano é o jeito mais rápido de transformar uma queda de rede em um novo pareamento. Quem decide é você, olhando o log.

Nos casos sem volta (401, 500 e 440), o processo encerra com código 0, sem erro. Um supervisor que reinicia o bot quando ele sai com erro, como o reinício automático de uma hospedagem, traria o processo de volta e criaria um loop: no 401 e no 500, com a mesma sessão inválida; no 440, expulsando a outra instância.

Por que a sessão some a cada restart?#

É a causa mais comum. A pasta de autenticação precisa ficar num disco que sobreviva ao reinício do processo. Ela some quando:

  • O bot roda em plataforma com disco efêmero, que recria o sistema de arquivos a cada deploy ou reinício. A documentação do whatsapp-web.js avisa que o LocalAuth precisa de um sistema de arquivos persistente e não serve para hosts efêmeros como o Heroku.
  • O caminho muda: você usa um caminho relativo e executa o bot de pastas diferentes.
  • Você reenvia o projeto inteiro (ZIP ou git) e a pasta de sessão é sobrescrita ou removida sem você perceber.

Para conferir, rode o bot, pareie, pare o processo e rode de novo. Se pedir QR ou código outra vez, a pasta não está sendo lida. Liste o conteúdo de AUTH_DIR antes e depois do restart: tem de haver um creds.json e vários arquivos de chaves.

Em produção, a documentação do Baileys recomenda guardar o estado de autenticação em banco de dados, não em arquivos, e trata o useMultiFileAuthState como um guia de como escrever esse armazenamento. Se você perde a pasta com frequência, um banco é o caminho. O guia de bot de WhatsApp 24/7 mostra o básico da sessão em disco.

Como saber se duas instâncias disputam a sessão?#

O sintoma é o código 440 (connectionReplaced) e um bot que cai a cada poucos segundos. Quando uma segunda conexão usa as mesmas credenciais, a anterior é derrubada. Se cada instância reconecta sozinha, elas ficam se expulsando.

Os culpados de sempre:

  • Você deixou o bot rodando no seu PC e subiu o mesmo no servidor.
  • O deploy novo sobe antes de o processo antigo morrer.
  • Um supervisor de processos como o PM2, ou um restart: always, mantém uma cópia viva que você não vê.
  • Você copiou a pasta de sessão para outro lugar e rodou os dois.

A correção é garantir uma única instância por sessão. Se precisa testar localmente, pareie um segundo número de teste em vez de reutilizar a pasta de produção.

O celular removeu o aparelho ou ficou inativo?#

O código 401 (loggedOut) quer dizer que o WhatsApp encerrou aquele aparelho vinculado. Duas causas:

  1. Alguém removeu o aparelho em Configurações, Dispositivos conectados, ou saiu da conta no celular.
  2. O celular principal ficou mais de 14 dias sem uso. Segundo a Central de Ajuda do WhatsApp, o celular não precisa ficar online para os aparelhos vinculados funcionarem, mas eles são desconectados se você não usar o celular por mais de 14 dias.

O limite de aparelhos também conta: a Central de Ajuda informa quantos aparelhos dá para vincular a uma conta. Se você já usa WhatsApp Web, app de desktop e outros bots no mesmo número, confira a lista em Dispositivos conectados e remova o que não usa.

Nos dois casos, a única saída é apagar a pasta de sessão e parear de novo. Reconectar com as credenciais antigas só repete o 401.

E no whatsapp-web.js?#

O whatsapp-web.js guarda a sessão com o LocalAuth, que salva os dados do navegador na pasta .wwebjs_auth por padrão. Sem authStrategy, o cliente não persiste nada e pede QR em toda execução:

js
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 ao WhatsApp."));
client.on("disconnected", (reason) => {
  // reason é "LOGOUT" ou um estado do WhatsApp Web, como CONFLICT ou UNPAIRED
  console.error("Desconectado:", reason);
});

client.initialize();

O evento disconnected recebe "LOGOUT" quando a sessão foi encerrada, ou um estado como CONFLICT (outra sessão assumiu, o equivalente ao 440) ou UNPAIRED (o aparelho foi desvinculado). As causas são as mesmas do Baileys: pasta perdida, duas instâncias, aparelho removido. Há ainda uma causa própria dele: como um Chromium roda ao lado do bot, a falta de memória pode derrubar o navegador e levar a conexão junto. Se o processo morre sem mensagem clara, olhe o consumo de RAM primeiro.

Como evitar que a sessão caia de novo?#

  • Uma sessão, uma instância. Nunca rode a mesma pasta em dois lugares.
  • Pasta persistente e fora do código. Defina AUTH_DIR por variável de ambiente e mantenha-a fora do repositório.
  • Registre o código de cada desconexão. Sem o log, você adivinha. Com ele, o diagnóstico leva um minuto.
  • Reconecte com espera, não em loop. Tentativas imediatas e infinitas só enchem o log e escondem a causa.
  • Use o celular principal de vez em quando. Abra o WhatsApp nele ao menos a cada duas semanas.
  • Não trate bot não oficial como garantido. Bibliotecas não oficiais podem quebrar quando o WhatsApp muda o protocolo, e usá-las contra os Termos de Serviço é risco seu. Para uso comercial, compare com a Cloud API oficial em Baileys, whatsapp-web.js ou Cloud API: ela usa webhook e token, sem depender de sessão de aparelho vinculado.

Como fazer isso na Square Cloud#

A Square Cloud é hospedagem self-service: você sobe o bot, escolhe a memória e controla o código. Você pode hospedar bots de WhatsApp feitos com Baileys, WPPConnect, whatsapp-web.js ou a Cloud API oficial. A pasta de autenticação fica no disco da aplicação, que persiste entre restarts e deploys, então a sessão continua conectada. Um novo ZIP sobrescreve só os arquivos que estão nele: deixe a pasta de autenticação fora do ZIP para não substituí-la.

Isso elimina a causa mais comum do QR repetido: a sessão que some a cada reinício. Os containers ficam sempre ligados, e o reinício automático, que vem ligado no deploy pelo painel, traz o processo de volta quando ele encerra com erro. Por isso o exemplo sai com código 0 quando a sessão é inválida. Você acompanha os códigos de desconexão nos logs em tempo real do painel ou da CLI. Cada aplicação de fundo, como um bot, tem no mínimo 256 MB de RAM; se usar whatsapp-web.js com Chromium, reserve mais memória.

Defina AUTH_DIR e WA_PHONE nas variáveis de ambiente da aplicação. A regra de uma instância por sessão continua valendo: ao subir o bot, desligue o que roda no seu PC. Veja os detalhes em hospedagem de bots de WhatsApp na Square Cloud.

Hospedagem de bots

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

Saiba mais

Perguntas frequentes

Por que meu bot de WhatsApp pede QR code toda vez que reinicia?

Porque a pasta de autenticação não sobrevive ao reinício. Isso acontece em disco efêmero, em redeploy que recria o container ou quando o código aponta para uma pasta diferente a cada execução. Salve a sessão em um caminho persistente.

O que significa o erro 401 loggedOut no Baileys?

O WhatsApp encerrou a sessão deste aparelho vinculado. Costuma ser porque alguém removeu o aparelho em Dispositivos conectados ou porque o celular principal ficou mais de 14 dias sem uso. Reconectar com as mesmas credenciais não adianta: é preciso apagar a pasta e parear de novo.

Posso rodar o mesmo bot no meu PC e no servidor ao mesmo tempo?

Não com a mesma sessão. A segunda conexão derruba a primeira com o código 440 (connectionReplaced), e as duas ficam se expulsando se cada uma reconectar sozinha. Use uma sessão por instância.

O bot de WhatsApp precisa que o celular fique ligado?

Os aparelhos vinculados funcionam sem o celular online, mas são desconectados se o celular principal ficar mais de 14 dias sem uso. Abrir o WhatsApp no celular de vez em quando basta.

Próximo artigoWebhook do Discord vs bot: qual usarWebhook do Discord só envia mensagens a um canal por uma URL; bot lê eventos, responde comandos e roda sempre online. Veja as diferenças e quando usar cada um.