Skip to content

QR scan succeeds but client disconnects with 'Max qrcode retries reached' due to stale change:ref listener #127089

@Adi1231234

Description

@Adi1231234

Is there an existing issue for this?

  • I have searched the existing issues.

Is this a problem caused by your code, or is it specifically because of the library?

  • I have double-checked my code carefully.

Describe the bug.

After a user successfully scans a QR code and WhatsApp Web begins loading (reaching 95-99% progress), the client unexpectedly disconnects with Max qrcode retries reached after about 2-3 minutes.

Two related problems in the QR handling code in Client.js:

1. change:ref listener is never cleaned up

The listener registered on AuthStore.Conn (line ~191) is never removed after a successful QR scan. When WhatsApp Web clears the ref property during/after authentication (setting it to null or undefined), the listener fires onQRChangedEvent with an invalid ref value, which:

  • Emits a malformed QR event (the QR string starts with "undefined," instead of "2@...")
  • Increments qrRetries past qrMaxRetries
  • Triggers a DISCONNECTED event with reason "Max qrcode retries reached"
  • Calls destroy(), killing the session even though authentication was in progress

2. qrRetries is never reset after a successful scan

The qrRetries counter only goes up. If the user waits through several QR refreshes before scanning, the counter is already close to the limit. Even if the null ref is guarded against, any legitimate post-scan QR event (e.g. if linking fails and WA Web falls back to QR) would immediately hit the retry limit, giving the user zero chance to try again.

Evidence from logs

The bug is clearly visible in the QR data:

  • Normal QR codes (before scan): qrLength=239, ref starts with 2@...
  • Spurious QR after scan: qrLength=146, ref is literally "undefined"

The math confirms it: 239 - 102 (normal ref length) + 9 ("undefined" length) = 146. The change:ref callback received undefined as the ref value.

Timeline from production logs:

08:15:29  QR #1 (initial)                    qrRetries=1
08:16:29  QR #2 (change:ref, normal rotate)  qrRetries=2
08:16:49  QR #3 (change:ref)                 qrRetries=3
08:17:09  QR #4 (change:ref)                 qrRetries=4  (= qrMaxRetries, no disconnect)
08:17:17  USER SCANS QR - loading 95% then 99%
08:20:14  QR #5 (change:ref, ref=undefined)  qrRetries=5 > 4 -> DISCONNECT!

Expected behavior

After a successful QR scan:

  1. The change:ref listener should stop emitting QR events
  2. The qrRetries counter should reset, so that if linking fails and WA Web falls back to QR, the user gets a fresh set of retry attempts

Steps to Reproduce the Bug or Issue

  1. Create a client with qrMaxRetries set to a low value (e.g., 4)
  2. Let 3-4 QR refresh cycles pass before scanning
  3. Scan the QR code - observe loading screen reaching 95-99%
  4. Wait 2-3 minutes for WhatsApp Web to clear/reset the ref
  5. Client disconnects with "Max qrcode retries reached" despite successful scan

The issue is timing-dependent: it requires enough QR refreshes before scan so that qrRetries is close to qrMaxRetries, and then a post-scan change:ref event pushes it over the limit.

Relevant Code

In src/Client.js, the change:ref listener (line ~191) is registered as an anonymous function with no cleanup:

window.AuthStore.Conn.on('change:ref', (_, ref) => {
    window.onQRChangedEvent(getQR(ref));
});

Three problems:

  1. No null guard: getQR(undefined) produces "undefined,..." instead of being silently ignored
  2. Never removed: The listener stays active after authentication, so any ref change (including cleanup to null/undefined) triggers a QR event and increments the retry counter
  3. Counter never resets: qrRetries only increments, so pre-scan QR refreshes eat into the post-scan budget

Proposed fix

  1. Reset qrRetries when loading_screen fires (the QR was successfully scanned)
  2. Guard against null/undefined ref in the change:ref callback
  3. Remove the change:ref listener when change:hasSynced fires (authentication complete)

PR: #127090

Browser Type

Chromium

WhatsApp Account Type

Standard

WhatsApp Web Version

2.3000+

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions