From 516dcffdc80443769d51774327dd658e384182cf Mon Sep 17 00:00:00 2001 From: michumichifu Date: Fri, 7 Aug 2026 17:49:44 -0400 Subject: [PATCH] fix(baileys): clear stale credentials when a 401 closes the initial connection An instance that loses its session becomes permanently unpairable. When the connection closes with loggedOut before any QR code has been issued, connectionUpdate() takes the isInitialConnection early return and leaves the stored credentials untouched. Those credentials are in a half-valid state: the session is gone, so registered is false, but the identity is still there (me and account survive). Baileys reads that on the next attempt and does the reasonable thing with the information it has: it tries to re-authenticate as that identity rather than requesting a pairing code. WhatsApp answers 401 because the session no longer exists, the connection closes, and we land back on the same early return. The instance loops roughly every ten seconds with hasQr: false and never emits a code, so GET /instance/connect keeps returning an empty qrCode object, the Manager dialog spins forever, and a phone scanning any older code is told to check its internet connection. Recovering from this currently requires stopping the container and deleting the Session row by hand, because an instance still running rewrites the credentials from memory as soon as they are removed. Recreating the instance also works, but it changes the instance id and token and breaks every n8n flow, Chatwoot inbox and third-party integration pointing at it. Clear the credentials on that path so the next attempt starts clean and can pair. The cleanup already existed inside logoutInstance(); it is extracted into clearStoredCredentials() and reused, so both paths stay in sync. --- .../whatsapp/whatsapp.baileys.service.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index 22839fd451..f383c4a1fd 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -322,6 +322,18 @@ export class BaileysStartupService extends ChannelStartupService { // is delayed. this.stateConnection = { state: 'close', statusReason: 401 }; + await this.clearStoredCredentials(); + } + + /** + * Wipe the stored auth credentials and mark the instance as closed. + * + * Extracted from logoutInstance() so the loggedOut path in connectionUpdate() + * can reuse it. Leaving half-valid credentials behind is what makes an + * instance impossible to pair again: Baileys sees the stored identity and + * tries to re-authenticate instead of requesting a pairing QR code. + */ + private async clearStoredCredentials() { const db = this.configService.get('DATABASE'); const cache = this.configService.get('CACHE'); const provider = this.configService.get('PROVIDER'); @@ -509,6 +521,21 @@ export class BaileysStartupService extends ChannelStartupService { const isInitialConnection = !this.instance.wuid && (this.instance.qrcode?.count ?? 0) === 0; if (isInitialConnection) { + // A loggedOut here means the credentials we had stored were rejected + // before any QR code could be issued. Returning without clearing them + // makes the instance permanently unpairable: on every later attempt + // Baileys finds the stored identity (`me` / `account`), tries to + // re-authenticate with it instead of asking for a pairing code, gets + // another 401, and comes back here. The instance loops forever with + // `hasQr: false` and /instance/connect keeps returning an empty code, + // so the QR dialog spins and the phone reports a network problem. + if (statusCode === DisconnectReason.loggedOut) { + this.logger.warn( + 'Stored credentials were rejected (401) before a QR code was issued; clearing them so the next attempt can pair', + ); + await this.clearStoredCredentials(); + } + this.logger.info('Initial connection closed, waiting for QR code generation...'); return; }