Skip to content

fix wwebjs chat list for lid message keys#748

Closed
SkywardLab wants to merge 1 commit into
rmyndharis:mainfrom
SkywardLab:fix/wwebjs-lid-last-received-key
Closed

fix wwebjs chat list for lid message keys#748
SkywardLab wants to merge 1 commit into
rmyndharis:mainfrom
SkywardLab:fix/wwebjs-lid-last-received-key

Conversation

@SkywardLab

Copy link
Copy Markdown

Description

Brief description of changes

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Checklist

  • Tests added/updated
  • Documentation updated
  • Lint passes
  • Self-reviewed

Screenshots (if applicable)

Related Issues

Closes #

@rmyndharis rmyndharis left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for the PR @SkywardLab — patching at the build layer is a reasonable idea for this class of upstream break. I've been over the diff, though, and I can't merge this as-is. A few things:

Merge-blocker — unrelated, regressive Dockerfile change

This is bundled in but has nothing to do with the lid-key fix:

-    chown -R openwa:openwa /app
+    chown -R openwa:openwa ./data

This narrows the openwa user's ownership from the entire /app tree to only ./data. The existing chown -R openwa:openwa /app was deliberate — the runtime reads its own app files, and the surrounding Chromium/XDG setup (Dockerfile:119-128, with HOME=/app/data, XDG_CONFIG_HOME/XDG_CACHE_HOME) was built around the current ownership model. Anything that writes outside ./data at runtime risks breaking. If narrowing ownership is intentional, it belongs in its own PR with its own justification — please drop this hunk.

Scope — this fixes chat-list, not media download (#747)

To set expectations on what this actually fixes: the exact-string block it patches (chat.lastReceivedKey._serialized in whatsapp-web.js/src/util/Injected/Utils.js ~L984 — the chat last-message resolver used by getChats) is one of several call sites broken by the WA Web _serialized rename. It does not touch Message.downloadMedia() (whatsapp-web.js/src/structures/Message.js ~L513), which is the path reported in #747 (inbound photo/file download). So this is a sibling symptom of the same rename, not a fix for #747. Could you note in the description which behavior/issue this is meant to fix? Right now the body is the empty template (Closes # is blank, no description).

The .toString() fallback isn't verified

chat.lastReceivedKey?._serialized || chat.lastReceivedKey?.toString?.() — if _serialized is genuinely gone (renamed by the minifier), toString() on a WA MsgKey isn't guaranteed to return a usable serialized id, so Msg.get(...) may still resolve nothing. That risks silently degrading to "no last message" rather than actually fixing the lookup. Have you confirmed a chat list comes back with real last messages on a broken build, or only that it no longer throws? The added test only asserts the patch text gets substituted; a test asserting the resolved id round-trips through Msg.get would carry real weight.

Fragility of the build-time patch

The OLD_BLOCK exact-string match means any whatsapp-web.js bump that touches that block turns the Docker build into throw new Error('Unsupported whatsapp-web.js Utils.js shape') — a hard image-build failure the next time the dep moves. The already-patched idempotency guard is good, but the throw-on-mismatch is sharp: a routine dependency bump would take down image builds with no prior warning. Prefer warn-and-continue (or version-gate the patch) over hard-fail.

PR hygiene

Empty description, no Closes #, no CI run, all checklist boxes unchecked. For a change that patches a vendored dependency at build time, the description should call out exactly what symptom it fixes and how it was verified on a live broken session.

Suggestion

The cleaner long-term fix for the _serialized rename is upstream — wwebjs/whatsapp-web.js#201832 normalizes the id at the root (Base._normalizeId), which covers downloadMedia, getChat, getQuotedMessage, and the lastReceivedKey path in one place, rather than patching each call site. I'd prefer to track that and bump the dep once it merges. If you'd like to pursue the build-time patch as a stopgap for the chat-list symptom specifically, I'm happy to re-review once the Dockerfile change is dropped and the fallback is verified against a live broken session — please rebase and push.

rmyndharis added a commit that referenced this pull request Jul 17, 2026
…#779)

The id-rename sweep taught the send (#762), ack and status (#773) paths to read `$1` when `_serialized` is absent. It missed the busiest path in the product.

buildIncomingMessageBase runs on every arriving message (adapter:517 onMessage) and every message sent from a linked phone (:593 onMessage_create), and read msg.id._serialized unguarded. Worse, RawMessageFields declared the id as `{ _serialized: string }`, so on a renamed build `$1` was not merely unread but unrepresentable — the fallback could not be written without a cast, and the `id: string` the mapper produced was undefined at runtime for every inbound message. No dedup key, no reply target, nothing for an ack to match, on the highest-volume path with no defence in depth. The build-time backport normally makes it moot, which is why it survived the sweep: the one path where a patcher failure hurts most is the one that assumed it never would.

The sentinel needed care. `?? ''` alone would have been a NEW bug: unlike saveOutgoingMessage, which normalizes an empty id to NULL at its chokepoint and documents why (the (sessionId, waMessageId) unique index is not partial, so NULL is exempt while a second `''` collides and the row is lost silently), the inbound persist passed incoming.id straight through. The same normalization is now applied where inbound messages are stored, and only then is `''` safe to mean "received, id unreadable".

Both tests fail against the previous mapper.

Also credits @SkywardLab in the chat-list changelog entry: #748 reported that site here first, independently, and the credit outlasts the PR thread.

Refs #747, #762, #773, #748.
@rmyndharis

Copy link
Copy Markdown
Owner

Thanks @SkywardLab — closing this, and I owe you a clear account of where it landed and where I got it wrong.

Your diagnosis was correct. chat.lastReceivedKey._serialized in whatsapp-web.js/src/util/Injected/Utils.js — the getChats last-message resolver — was genuinely broken by the WA Web 2.3000.x _serialized$1 rename, and it's a distinct site from the media-download symptom in #747. It was also the first report of that specific site in this tracker. You were right about the delivery mechanism too: patching the installed dependency at build time was the right call for this class of upstream break, and that is what main now does.

What superseded this, and where

scripts/wwebjs-201832.patch (merged in #759, 3e3c167; hardened in #772, ea2680b) backports upstream wwebjs/whatsapp-web.js#201832 and rewrites the exact block your script targeted:

-            const lastMessage = chat.lastReceivedKey
+            const _lastReceivedKeyId = chat.lastReceivedKey
+                ? chat.lastReceivedKey._serialized || chat.lastReceivedKey.$1
+                : null;
+            const lastMessage = _lastReceivedKeyId
                 ? window
                       .require('WAWebCollections')
-                      .Msg.get(chat.lastReceivedKey._serialized) ||
+                      .Msg.get(_lastReceivedKeyId) ||

It runs at Dockerfile:97 right after npm ci, and since #759 also from package.json's postinstall, so source installs get it too — a gap this PR didn't cover.

On the fallback itself: you used chat.lastReceivedKey?.toString?.(); the shipped patch uses || chat.lastReceivedKey.$1. $1 is the actual minified rename and what upstream settled on. That resolves the toString() question I raised — the instinct to add a fallback was right, that particular mechanism wasn't.

Where I have to correct myself

On the hard-fail. I told you the throw-on-mismatch was too sharp and to prefer warn-and-continue or a version gate. The patcher I shipped hard-fails the image build on drift as well — Dockerfile:97 runs it without --best-effort, deliberately, so a drifted tree aborts rather than ships half-patched. That half of my objection was a standard I didn't hold my own code to, and you'd have been entitled to push back. What the shipped version does have that yours didn't is the other half: it self-disables once the installed whatsapp-web.js normalizes ids itself, so the dependency bump we're both waiting on stands it down instead of breaking builds. That's the real difference, and it's narrower than I made it sound.

On the process. I closed my review with "if you'd like to pursue the build-time patch as a stopgap, I'm happy to re-review... please rebase and push." About 25 hours later I opened #758/#759 doing that stopgap myself and merged it, without coming back here to tell you. That's on me. I left you holding an open invitation to do work I then did myself, and you should have heard it in this thread rather than from the changelog. The plan itself hasn't changed — upstream #201832 is still open and the backport still stands down when it lands — only who did the interim work, and I should have said so here.

On priority, since I'd rather state it than have it inferred: upstream #201832 was opened at 2026-07-15T00:25:18Z, about ten hours before this PR, and already contained the lastReceivedKey hunk — that's why my review pointed you at it. Your finding was independent and correct and first here; it wasn't the first fix for that block. I'm not going to claim otherwise in either direction.

The chown -R openwa:openwa /app./data hunk was right to drop — Dockerfile:123 still carries /app ownership deliberately.

Why closing rather than asking for a rebase

There's nothing left to rebase onto. The block is already rewritten on main, so your script's OLD_BLOCK wouldn't match and it would throw Unsupported whatsapp-web.js Utils.js shape if it stayed wired into the Dockerfile — and unwired it'd be dead code. Either way a rebase would be work that can't land, and I'm not going to ask you for that.

I've credited #748 in the changelog entry for the chat-list fix (d0a1869), since that outlasts this thread. If you're on 2.3000.x and still don't get real last messages on main, please open a fresh issue and I'll take it directly.

@rmyndharis rmyndharis closed this Jul 17, 2026
@SkywardLab
SkywardLab deleted the fix/wwebjs-lid-last-received-key branch July 19, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants