Skip to content

fix: use WA's own LID resolution for block/unblock#201671

Merged
BenyFilho merged 3 commits intowwebjs:mainfrom
Adi1231234:fix/block-unblock-lid-resolution
Mar 24, 2026
Merged

fix: use WA's own LID resolution for block/unblock#201671
BenyFilho merged 3 commits intowwebjs:mainfrom
Adi1231234:fix/block-unblock-lid-resolution

Conversation

@Adi1231234
Copy link
Copy Markdown
Contributor

Summary

block() and unblock() have two issues:

  • block() passes a Chat object to blockContact(), which expects a Contact model. It works by accident because both have .id, but it's the wrong type. The getChat() call also creates an unnecessary chat as a side effect via findOrCreateLatestChat.
  • unblock() uses the synchronous Contact.get() which returns undefined when the contact isn't in the local cache yet.

With blocklist migration enabled (isBlocklistMigrated() === true), blockContact() internally calls S() which needs either a LID or an existing chat with accountLid to resolve the target. The old getChat() workaround created a chat to satisfy this, but the proper way is to resolve the contact's LID directly.

This PR uses WAWebBlockContactUtils.getContactToBlockOnlyUseIfNoAssociatedChat(), which is WA's own utility for this exact scenario. It calls getCurrentLidContact() to convert PN contacts to their LID equivalent without creating unnecessary chats.

Tested in WhatsApp Web DevTools: block + unblock cycle works correctly for contacts with and without existing chats.

Test plan

  • Block a contact you have an existing chat with
  • Block a contact you have never interacted with before
  • Unblock both contacts
  • Verify no unnecessary chats are created

block() was passing a Chat object to blockContact() which expects a
contact. unblock() was using synchronous Contact.get() which returns
undefined if the contact isn't cached.

with blocklist migration enabled, blocking a PN contact without a chat
fails because the internal S() function needs a LID or an existing chat
to resolve the accountLid. The old getChat() approach worked around this
by creating a chat via findOrCreateLatestChat, but that's a side effect
and passes the wrong type.

use WAWebBlockContactUtils.getContactToBlockOnlyUseIfNoAssociatedChat()
instead, which is WA's own utility for this exact case. It resolves the
contact's LID via getCurrentLidContact() without needing to create a
chat.
@github-actions github-actions Bot added the api changes API modifications label Mar 18, 2026
Adi1231234 added a commit to Adi1231234/whatsapp-web.js that referenced this pull request Mar 18, 2026
moved to a dedicated PR (wwebjs#201671) with a proper fix using
wawebblockcontactutils.getContactToBlockOnlyUseIfNoAssociatedChat()
for correct LID resolution.
Adi1231234 added a commit to Adi1231234/whatsapp-web.js that referenced this pull request Mar 18, 2026
moved to a dedicated PR (wwebjs#201671) with a proper fix using
wawebblockcontactutils.getContactToBlockOnlyUseIfNoAssociatedChat()
for correct LID resolution.
@BenyFilho BenyFilho added the approved Confirmed by maintainers label Mar 18, 2026
@lindionez
Copy link
Copy Markdown
Contributor

lindionez commented Mar 18, 2026

This resolved contact.unblock() for me, which hadn't been working for about 15 days. However, the contact still marks isBlocked: false even when the contact is blocked.

It was tested on 4 different numbers running the code.

@github-actions github-actions Bot added the utility Utility code label Mar 19, 2026
iscontactblocked on PN contacts returns false because the Blocklist
only contains LID entries. Use getAlternateUserWid() to resolve
the PN/LID mapping and check the Blocklist directly, matching WA
web's own $Contact$p_3 fallback logic.
@Adi1231234 Adi1231234 force-pushed the fix/block-unblock-lid-resolution branch from 0ef58b2 to 00ee4d9 Compare March 19, 2026 19:30
@Adi1231234
Copy link
Copy Markdown
Contributor Author

@BenyFilho Thanks for the approval!
@lindionez Thanks for reporting this! That bug was actually there before my changes but I went ahead and fixed it anyway. The blocklist stores LIDs so when you look up a phone number contact it never finds it. I'm now using getAlternateUserWid() to check the right ID against the blocklist, which is how WA handles it internally.
Would love to hear if it works on your end!

Copy link
Copy Markdown
Contributor

@lindionez lindionez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THANK YOU VERY MUCH, I had been without this function for about 2 weeks, it worked perfectly.

BenyFilho pushed a commit that referenced this pull request Mar 24, 2026
…handling (#127098)

* fix: prevent store mutation in getContact/getChatModel LID handling

getcontact() and getChatModel() overwrite .id directly on live Backbone
model references from WhatsApp Web's Contact/Participant store. This
permanently corrupts the store for the lifetime of the session, causing
all subsequent lookups for the same contact to crash with:
- "Cannot read properties of undefined (reading '_serialized')"
- "Data passed to getter must include an id property"

the fix resolves LID to phone on the serialized copy only, never
touching the live store model.

fixes #127054

* perf: use BusinessProfile.find() instead of fetchBizProfile()

businessprofile.find() checks the local cache first and only fetches
from the server when the profile is missing, while fetchBizProfile()
always makes a network call (~85-100ms per contact). This significantly
reduces latency when getContact is called repeatedly for the same
business contacts.

closes #201656

co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove unnecessary try/catch around BusinessProfile.find()

businessprofile.find() never throws for non-business contacts - it returns
a BusinessProfile model with profileOptions: null, not an error. The comment
was factually incorrect. The existing profileOptions guard handles the
non-business case correctly without any exception handling.

verified in WhatsApp Web DevTools: find() returns a valid object for regular,
business, LID, and even non-existent contacts. Only throws when called without
an id, which cannot happen here.

co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: simplify contact/chat model utils via native WA functions

replace the O(n²) LID participant loop with WAWebLidMigrationUtils.toPn()
which resolves LID WIDs via LidPnCache in O(1). Remove the findContact
wrapper since Contact.find() accepts strings directly. Use
wawebwidfactory.createWidFromWidLike() for safe isLid() calls that handle
plain-object contact ids without WID prototype methods.

co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* perf: skip BusinessProfile.find() for non-business contacts

wa's own source guards this behind isBusiness || isEnterprise
(WAWebUseBusinessProfile.react). No point querying business profiles
for regular contacts - saves a wasted IQ roundtrip (~80ms) per call.

* revert: remove block/unblock changes from this PR

moved to a dedicated PR (#201671) with a proper fix using
wawebblockcontactutils.getContactToBlockOnlyUseIfNoAssociatedChat()
for correct LID resolution.

* fix: convert contactId to Wid before collection find() calls

contact.find() and BusinessProfile.find() reject plain strings when
the entry is not cached or stale, throwing "gadd called without an id
attr". Use createWid(contactId) to ensure a proper Wid object is passed.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@BenyFilho BenyFilho merged commit 016a56b into wwebjs:main Mar 24, 2026
4 checks passed
DouglasLopesS added a commit to DouglasLopesS/whatsapp-web.js that referenced this pull request Apr 27, 2026
…handling (wwebjs#127098)

* fix: prevent store mutation in getContact/getChatModel LID handling

getcontact() and getChatModel() overwrite .id directly on live Backbone
model references from WhatsApp Web's Contact/Participant store. This
permanently corrupts the store for the lifetime of the session, causing
all subsequent lookups for the same contact to crash with:
- "Cannot read properties of undefined (reading '_serialized')"
- "Data passed to getter must include an id property"

the fix resolves LID to phone on the serialized copy only, never
touching the live store model.

fixes wwebjs#127054

* perf: use BusinessProfile.find() instead of fetchBizProfile()

businessprofile.find() checks the local cache first and only fetches
from the server when the profile is missing, while fetchBizProfile()
always makes a network call (~85-100ms per contact). This significantly
reduces latency when getContact is called repeatedly for the same
business contacts.

closes wwebjs#201656

co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove unnecessary try/catch around BusinessProfile.find()

businessprofile.find() never throws for non-business contacts - it returns
a BusinessProfile model with profileOptions: null, not an error. The comment
was factually incorrect. The existing profileOptions guard handles the
non-business case correctly without any exception handling.

verified in WhatsApp Web DevTools: find() returns a valid object for regular,
business, LID, and even non-existent contacts. Only throws when called without
an id, which cannot happen here.

co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: simplify contact/chat model utils via native WA functions

replace the O(n²) LID participant loop with WAWebLidMigrationUtils.toPn()
which resolves LID WIDs via LidPnCache in O(1). Remove the findContact
wrapper since Contact.find() accepts strings directly. Use
wawebwidfactory.createWidFromWidLike() for safe isLid() calls that handle
plain-object contact ids without WID prototype methods.

co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* perf: skip BusinessProfile.find() for non-business contacts

wa's own source guards this behind isBusiness || isEnterprise
(WAWebUseBusinessProfile.react). No point querying business profiles
for regular contacts - saves a wasted IQ roundtrip (~80ms) per call.

* revert: remove block/unblock changes from this PR

moved to a dedicated PR (wwebjs#201671) with a proper fix using
wawebblockcontactutils.getContactToBlockOnlyUseIfNoAssociatedChat()
for correct LID resolution.

* fix: convert contactId to Wid before collection find() calls

contact.find() and BusinessProfile.find() reject plain strings when
the entry is not cached or stale, throwing "gadd called without an id
attr". Use createWid(contactId) to ensure a proper Wid object is passed.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api changes API modifications approved Confirmed by maintainers utility Utility code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants