fix: tolerate WhatsApp Web renaming the message key _serialized to $1 - #201848
fix: tolerate WhatsApp Web renaming the message key _serialized to $1#201848kristoflouviere wants to merge 2 commits into
Conversation
WhatsApp Web renamed the message key's `_serialized` property to `$1`. getChatModel
reads `chat.lastReceivedKey._serialized`, which now yields undefined and reaches
IndexedDB as `Msg.getMessagesById([undefined])`, throwing:
DataError: Failed to execute 'get' on 'IDBObjectStore': No key or key range specified.
getChats() maps getChatModel over every chat under Promise.all, so a single affected
chat rejects the whole batch and surfaces to callers as an opaque minified error
(commonly reported as "r: r") while the client is CONNECTED and WhatsApp Web is fully
loaded. Chat ids are NOT affected -- they still carry `_serialized` -- which is why the
failure does not look like the rename.
Measured on two live sessions (WA Web 2.3000.1043280533, whatsapp-web.js 1.34.7), by
catching the error inside page.evaluate so the in-page stack survives:
session A: 1253 chats, 916 with a lastReceivedKey, 0 of which had `_serialized`
-> getChatModel threw for those 916 and succeeded for the other 337
session B: 515 chats, 498 with a lastReceivedKey, 0 with `_serialized`
Chats with no last message skip the block entirely, which is exactly the observed
337/916 split. Reading `_serialized ?? $1` resolved the key on every affected chat.
Adds window.WWebJS.getMsgKeyId(key). It prefers `_serialized`, so behaviour is unchanged
wherever that is still present, and returns undefined so callers skip the lookup instead
of querying a store with a nullish key. Applied to the raw message keys read by
getChatModel, sendMessage and editMessage (getMessageModel is unaffected: it reads a
serialize()d model, which still produces `_serialized`).
Refs wwebjs#201845, wwebjs#201844, wwebjs#201846
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… rename
The rename reaches getMessageModel too: `message.serialize()` returns an `id` carrying
`$1` and no `_serialized`, so every consumer of `message.id._serialized` -- including this
library's own Message structure, and any caller keying on a message id -- silently gets
undefined.
Measured on a live session (WA Web 2.3000.1043280533, 2753 messages in memory): every
serialized model came back with `id: { fromMe, remote, id, $1 }` and `_serialized:
undefined`.
The failure mode is quiet and severe rather than loud: code that dedupes on
`msg.id._serialized` sees the same undefined key for every message, so a consumer keeping
a Set of seen ids processes exactly one message and silently drops the rest -- no error,
no log, just an ingestion path that looks alive and captures nothing.
Restores `_serialized` in getMessageModel next to the existing `msg.id.remote`
normalisation, using the same getMsgKeyId helper, so the whole downstream surface keeps
working instead of each caller having to learn about `$1`. Only fills it in when absent,
so nothing changes once/if WhatsApp Web restores the old name.
Refs wwebjs#201846, wwebjs#201844
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Tested this and it perfectly fixes the r: r IndexedDB crashes on my headless Oracle Cloud setup. +1 for this surgical approach! |
|
It worked perfectly for me. Thanks! But this ultimately requires patch in #201847 as well |
|
Few misses still: #1 — Poll votesThis is a real uncovered path, assuming When a live poll-vote update arrives, const parentMsgKey = vote.pollUpdateParentKey;
let parentMessage = Msg.get(parentMsgKey._serialized);
if (!parentMessage) {
const fetched = await Msg.getMessagesById([
parentMsgKey._serialized,
]);
}If that key now looks like: { $1: '...', remote: ..., id: ... }both lookups receive The resulting this.parentMsgKey = data.parentMsgKey;So consumers reading ScopeThis mainly affects:
It does not necessarily break Suggested minimal fixUse const parentMsgKeyId = window.WWebJS.getMsgKeyId(parentMsgKey);
let parentMessage = parentMsgKeyId
? Msg.get(parentMsgKeyId)
: null;
if (!parentMessage && parentMsgKeyId) {
const fetched = await Msg.getMessagesById([parentMsgKeyId]);
parentMessage = fetched?.messages?.[0] || null;
}Then either serialize #2 — Nested message IDsThere are two nested fields: message.latestEditMsgKey
message.protocolMessageKeyBoth are declared as key._serializedYour normalization in msg.idIt does not recursively repair those nested keys.
|
| Path | Likely impact | Recommendation |
|---|---|---|
| Poll-vote parent key | Event processing may fail | Worth fixing if polls matter |
protocolMessageKey |
Revoked message ID missing | Fix if handling delete-for-everyone events |
latestEditMsgKey |
Public nested ID missing | Low priority unless consumed |
|
This is the patch that's working for me https://github.com/vaibhavpandeyvpz/wappmcp/tree/main/patches until changes in this PR are released |
|
Btw , has there been a discussion about bundling the current whatsappweb into the package , or agressively caching them post deploy so upstream changes arent as likely to break things ? (I imagine whatsapp has to keep up the older apis for a while anyways ) 🤔 |
|
Confirmed @vaibhavpandeyvpz's poll-vote point on a live 2.3000.x session: Happy to help however's easiest for you - I can open a full PR with all the fixes bundled together, or if you'd rather keep everything in this one, I'm glad to send the changes your way. Whatever works best. 🙂 |
please tell me all changes... |
The bug
WhatsApp Web renamed the message key's
_serializedproperty to$1.getChatModelreadschat.lastReceivedKey._serialized(Utils.js#L984-L997), which now yieldsundefinedand reaches IndexedDB asMsg.getMessagesById([undefined]):getChats()mapsgetChatModelover every chat underPromise.all, so one affected chat rejects the entire batch — surfacing to callers as an opaque minified error (widely reported asr: r) while the client isCONNECTEDand WhatsApp Web is fully loaded.Chat ids are not affected — they still carry
_serialized. That is why this doesn't look like the$1rename, and why fixes that normalize ids in the Node-sidestructures/layer don't reach it: the throw happens in-page, insidegetChatModel, before anything is returned.Evidence
Measured on two live sessions (WA Web
2.3000.1043280533, whatsapp-web.js1.34.7) by catching the error insidepage.evaluateso the in-page stack survives the CDP boundary (otherwise it collapses toname: message, i.e.r: r):lastReceivedKey_serializedgetChatModelresultChats with no last message skip the block entirely — which is exactly the observed 337 / 916 split. Sampled keys look like:
Re-running the same lookup with
_serialized ?? $1returned the message on every affected chat.The fix
Adds
window.WWebJS.getMsgKeyId(key):_serialized, so behaviour is unchanged wherever it is still present;undefinedwhen neither exists, so callers skip the lookup rather than querying a store with a nullish key.Applied to the three places a raw (un-
serialize()d) message key is read:getChatModel,sendMessage,editMessage.getMessageModelis deliberately untouched — it reads aserialize()d model, which still produces_serialized.msg.id.remote._serializedis also untouched:remoteis a chat id, which the rename didn't affect.Only
getChatModelis verified against live sessions;sendMessage/editMessageread a raw key of the same shape and get the same one-token change. The helper is a no-op where_serializedstill exists, so it cannot regress either path.Refs #201845, #201844, #201846
Prettier + the existing style are unchanged (
prettier --checkpasses; diff is 1 file, +24/−7).