Pular para conteúdo

Bug WhatsApp após migração de VPS: mensagem entregue, bot mudo

Categoria Troubleshooting

Você migrou o OpenClaw para um VPS novo. Tudo subiu: Docker rodando, agente respondendo no terminal, canal WhatsApp conectado com QR code lido. Mandou uma mensagem de teste. Dois tiques azuis — entregue. Resposta do bot: nenhuma. Silêncio.

Esse bug é invisível porque tudo parece funcionar. O WhatsApp confirma entrega, os logs do agente não mostram erro, e o canal aparece como “connected” (conectado). O problema está uma camada abaixo: no formato do número que o Baileys (a biblioteca que conecta o OpenClaw ao WhatsApp) usa internamente.


SintomaCausaSolução
Mensagem entregue (dois tiques), bot não respondeBaileys envia JID com 8 dígitos; allowFrom só tem formato de 9 dígitosIncluir ambos os formatos no allowFrom, ou usar regex de normalização

O que aconteceu

Dois tiques azuis significam que o servidor do WhatsApp entregou a mensagem ao dispositivo de destino. Não significa que o aplicativo (ou bot) processou essa mensagem. Entrega é protocolo de rede; processamento é lógica de aplicação.

O OpenClaw recebeu a mensagem. Mas antes de processá-la, ele verifica se o remetente está na lista allowFrom (a lista de números autorizados a falar com o bot). Essa verificação usa o JID (o identificador interno que o WhatsApp usa para cada número) — não o número que aparece na tela do celular.

E aqui mora o problema: o JID que o Baileys gera nem sempre corresponde ao formato que você colocou no allowFrom.


Como números brasileiros funcionam no WhatsApp

Números brasileiros de celular têm 9 dígitos locais desde 2012 (o “nono dígito”). Mas o WhatsApp, internamente, às vezes usa o formato antigo de 8 dígitos para a parte do JID. O Baileys herda esse comportamento.

Exemplo com número fictício:

número exibido no celular:  +55 11 90000-1234
                                 ──────────
                                 9 dígitos locais

formato "moderno" (9 dígitos):
  JID = 5511900001234@s.whatsapp.net
        ──┬─ ──┬──────
          │    └─ 9 dígitos (com o 9 na frente)
          └─ código país + DDD

formato "legado" (8 dígitos):
  JID = 551100001234@s.whatsapp.net
        ──┬─ ──┬─────
          │    └─ 8 dígitos (sem o 9 na frente)
          └─ código país + DDD

Qual formato o Baileys usa depende do estado interno da sessão. Uma instância antiga que já tinha o contato salvo pode ter normalizado para 9 dígitos. Uma instância nova — como a que você criou ao migrar de VPS — pode receber o JID legado de 8 dígitos diretamente do servidor do WhatsApp.


Por que funcionava antes

Na VPS antiga, a sessão do Baileys já existia há semanas ou meses. Durante esse tempo, o WhatsApp sincronizou os contatos e normalizou os JIDs para o formato de 9 dígitos. Seu allowFrom tinha 5511900001234 e tudo batia.

Ao migrar, você criou uma sessão nova. Sessão nova = sem histórico de contatos = sem normalização automática. O WhatsApp envia o JID no formato que bem entender — e para números brasileiros, frequentemente é o legado de 8 dígitos.

VPS antiga (sessão madura):
  mensagem chega → JID: 5511900001234 → allowFrom match → bot responde

VPS nova (sessão fresca):
  mensagem chega → JID: 551100001234  → allowFrom não encontra → descarta
                         ─────────────
                         8 dígitos — sem o 9

O log do agente não mostra erro porque descartar mensagens de números não autorizados é comportamento esperado. Do ponto de vista do bot, ele fez a coisa certa: ignorou um número desconhecido.


A solução

Opção 1: incluir ambos os formatos

A forma mais direta. No seu config.json (ou equivalente), liste o número com e sem o nono dígito:

{
  "allowFrom": [
    "5511900001234",
    "551100001234",
    "5521900005678",
    "552100005678"
  ]
}

Funciona imediatamente, sem dependência de código. Desvantagem: cada número ocupa duas linhas.

Opção 2: normalizar na chegada

Uma função que converte qualquer JID brasileiro para um formato canônico antes da verificação. Assim o allowFrom precisa de uma entrada só por número:

function normalizarJidBR(jid) {
  // Remove o sufixo do WhatsApp, ficando só com os dígitos
  const numero = jid.replace(/@s\.whatsapp\.net$/, '')

  // Padrão brasileiro: 55 + DDD(2) + número
  // Se tem 12 dígitos (55 + 2 + 8), é formato legado — insere o 9
  if (/^55\d{2}\d{8}$/.test(numero)) {
    const pais = numero.slice(0, 2)   // "55"
    const ddd = numero.slice(2, 4)    // "11", "21", etc.
    const local = numero.slice(4)     // 8 dígitos
    return `${pais}${ddd}9${local}`   // insere o 9 → 13 dígitos
  }

  // Já tem 13 dígitos (55 + 2 + 9) ou não é BR — retorna como está
  return numero
}

No ponto onde o OpenClaw verifica o allowFrom, normalize antes de comparar:

// Antes (quebra com JID legado):
const autorizado = config.allowFrom.includes(remetente)

// Depois (funciona com qualquer formato):
const remetenteNormalizado = normalizarJidBR(remetente)
const autorizado = config.allowFrom.includes(remetenteNormalizado)

Com essa abordagem, o allowFrom sempre usa o formato de 9 dígitos e a normalização cuida do resto.


Diagnóstico rápido

Se o bot parou de responder após qualquer mudança de infra (migração, reinstalação, troca de número), siga essa árvore:

Bot não responde?


openclaw channels status       ← canal está "connected"?
    │                              NÃO → reconectar QR code

openclaw logs --since 1h       ← mensagem aparece nos logs?
    │                              NÃO → problema de rede/firewall

Procure "message received"     ← log mostra o JID do remetente?
    │                              SIM → anote o JID

Compare com allowFrom          ← JID bate com alguma entrada?
    │                              NÃO → problema de formato (este post)

Verifique qtd de dígitos       ← 12 dígitos = legado, 13 = moderno

Troubleshooting

O problema só acontece com números brasileiros? Sim. A dualidade 8/9 dígitos é específica do Brasil (o “nono dígito” adicionado entre 2012-2016). Números de outros países têm formato fixo e o JID corresponde ao número exibido.

Posso forçar o Baileys a sempre usar 9 dígitos? Não diretamente. O formato do JID vem do servidor do WhatsApp durante o handshake da sessão. O Baileys repassa o que recebe. A normalização precisa acontecer no seu código, não na biblioteca.

Isso pode acontecer de novo sem migração? Pode. Qualquer evento que recrie a sessão do Baileys — logout/login, corrupção do arquivo de sessão, atualização do Baileys que limpa cache — pode mudar o formato do JID. A normalização (opção 2) é a solução definitiva porque não depende do estado da sessão.


Próximo passo

Esc