Skip to content

fix: prevent stale change:ref listener from triggering false QR disconnect#127090

Closed
Adi1231234 wants to merge 1 commit intowwebjs:mainfrom
Adi1231234:fix/qr-retry-after-scan
Closed

fix: prevent stale change:ref listener from triggering false QR disconnect#127090
Adi1231234 wants to merge 1 commit intowwebjs:mainfrom
Adi1231234:fix/qr-retry-after-scan

Conversation

@Adi1231234
Copy link
Copy Markdown
Contributor

@Adi1231234 Adi1231234 commented Mar 2, 2026

Fixes #127089

Problem

Two related bugs in the QR handling code:

  1. The change:ref listener on AuthStore.Conn is never removed after a successful QR scan. When WhatsApp Web clears the ref during/after authentication (setting it to null/undefined), the listener fires onQRChangedEvent with an invalid ref, incrementing qrRetries past qrMaxRetries and triggering a spurious "Max qrcode retries reached" disconnect while authentication is already in progress.

  2. The qrRetries counter never resets. Pre-scan QR refreshes consume retry attempts, so any post-scan QR event (even legitimate) immediately hits the limit. If linking fails and WA Web falls back to QR mode, the user gets zero retry attempts.

Changes

Three layered fixes in src/Client.js, each addressing a different aspect:

  1. Reset qrRetries on loading_screen: When the loading screen fires (QR was successfully scanned and authentication begins), reset the counter to 0. If the linking fails and WA Web falls back to QR, the user gets a fresh set of retry attempts.

  2. Null guard on change:ref: Skip onQRChangedEvent when ref is null/undefined. Prevents malformed QR strings (starting with "undefined,") from being emitted and counted as retry attempts.

  3. Listener cleanup on change:hasSynced: Remove the change:ref listener when authentication completes (change:hasSynced on AuthStore.AppState, which is the same object as WAWebSocketModel.Socket). Prevents any stale QR events from firing after the client is fully connected.

How it was found

Production logs showed a client reaching loading 95-99% after a successful QR scan, then disconnecting 3 minutes later. The final QR event had qrLength=146 (vs normal 239), confirming the ref was the literal string "undefined". The qrRetries counter (already at 4 from normal pre-scan QR refreshes) was pushed to 5, exceeding qrMaxRetries=4.

@Adi1231234
Copy link
Copy Markdown
Contributor Author

Hey @purpshell @BenyFilho 👋

Would any of you have a chance to review this? It fixes a pretty annoying bug where QR scan works but the client disconnects because an old listener fires.

Happy to hop on Discord or chat if anything needs clarifying!

@BenyFilho
Copy link
Copy Markdown
Member

Hey @purpshell @BenyFilho 👋

Would any of you have a chance to review this? It fixes a pretty annoying bug where QR scan works but the client disconnects because an old listener fires.

Happy to hop on Discord or chat if anything needs clarifying!

Need user tests to validate it, and update your changes with branch main

@Adi1231234 Adi1231234 force-pushed the fix/qr-retry-after-scan branch from f6b972a to 5c2a4ce Compare March 9, 2026 23:05
@Adi1231234
Copy link
Copy Markdown
Contributor Author

Hey @BenyFilho, just rebased onto the latest main, everything is up to date and CI is green.

I keep having to rebase these because other PRs get merged and create conflicts with my open ones. Would love to get them merged so I can stop chasing this 😅

About the user tests you mentioned, what exactly do you mean by that? I'm happy to help with whatever is needed to get these moving.

@BenyFilho
Copy link
Copy Markdown
Member

Hey @BenyFilho, just rebased onto the latest main, everything is up to date and CI is green.

I keep having to rebase these because other PRs get merged and create conflicts with my open ones. Would love to get them merged so I can stop chasing this 😅

About the user tests you mentioned, what exactly do you mean by that? I'm happy to help with whatever is needed to get these moving.

Need user tests to validate it, and update your changes with branch main

@Adi1231234 Adi1231234 force-pushed the fix/qr-retry-after-scan branch from 5c2a4ce to 1606b19 Compare March 10, 2026 01:40
@github-actions github-actions bot added the api changes API modifications label Mar 10, 2026
the change:ref listener on AuthStore.Conn was never removed after a
successful QR scan. When WhatsApp Web clears the ref after
authentication begins, the listener would fire onQRChangedEvent with
an invalid ref, causing a spurious 'Max qrcode retries reached'
disconnect.

three fixes:
1. Reset qrRetries when loading_screen fires
2. Guard against null/undefined ref in the change:ref callback
3. Remove the change:ref listener once change:hasSynced fires
@Adi1231234 Adi1231234 force-pushed the fix/qr-retry-after-scan branch from 1606b19 to 18cdaf8 Compare March 10, 2026 01:48
@Adi1231234
Copy link
Copy Markdown
Contributor Author

Adi1231234 commented Mar 10, 2026

Hey @BenyFilho, thanks for the follow up!
I see that @tuyuribr approve that.
I fixed the conflicts and the CI

@Adi1231234
Copy link
Copy Markdown
Contributor Author

Closing in favor of #201653, which consolidates this PR together with #127083 into a single, more comprehensive fix.

The new PR includes all the changes from both PRs plus additional fixes (listener cleanup, concurrency guard, atomic hasSynced check, qrRetries reset) - all validated with A/B diagnostic testing across 5 real-world scenarios.

Thanks everyone for the feedback and reviews here - it really helped shape the final solution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api changes API modifications waiting for testers Needs testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

3 participants