Skip to content

fix(engine): return the real id for forwarded messages on whatsapp-web.js so delivery status advances#341

Closed
rmyndharis wants to merge 1 commit into
mainfrom
fix/wwjs-forward-message-id
Closed

fix(engine): return the real id for forwarded messages on whatsapp-web.js so delivery status advances#341
rmyndharis wants to merge 1 commit into
mainfrom
fix/wwjs-forward-message-id

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

Problem

Forwarding a message on the whatsapp-web.js engine returned a synthetic fwd_<id> — the underlying library's Message.forward() resolves to void, so the adapter fabricated an id. The delivery-ack matcher keys strictly on the stored waMessageId, and the real ack carries the sent copy's real id, so it never matched: forwarded messages were stuck at SENT forever and webhook / n8n consumers (keyed on the returned message id) could never correlate the ack. Baileys already returns the real id, so this was also a cross-engine contract drift.

Fix

After forward(), the adapter reads the sent copy back from the destination chat (the most recent outgoing message) and returns its real id._serialized, so the ack matches and the status advances — aligning whatsapp-web.js with Baileys.

Hardened per review:

  • Best-effort recovery. The forward has already happened, so the read-back is wrapped so it can never turn a successful forward into a reported failure (e.g. a transient browser/page error). It also null-guards the destination chat lookup.
  • Explicit-unknown fallback. When the sent copy can't be identified, the adapter returns an empty id and message.service leaves the row's waMessageId unset (NULL). A null id matches no ack and collides with nothing — unlike a synthetic fwd_ id (un-correlatable) or the source id (which would share waMessageId with the source message's own row and let a single ack mis-drive both).

Known limitation

Recovery selects the most-recent outgoing message by timestamp, so two near-simultaneous forwards/sends to the same destination chat could mis-identify the copy. This is documented inline and is a clear net improvement over the previous always-broken behaviour (it is correct in the dominant single-forward case); a content/source-id match could tighten it later.

Compatibility

MessageResult shape unchanged; non-breaking. SemVer: patch.

Tests

  • Returns the real id of the forwarded copy read back from the destination chat (not fwd_<id>).
  • Returns an explicit-unknown (empty) id when the copy can't be identified.
  • A throw during post-forward recovery does not surface as a failed forward.
  • Full backend suite 731/731; dashboard build + lint clean.

…b.js so delivery status advances

The whatsapp-web.js engine returned a synthetic fwd_<id> for a forwarded message because the library's forward() yields no id, and the delivery-ack matcher keys on the stored id — so a forward never advanced past SENT and webhook/n8n consumers could not correlate it (Baileys already returns the real id). The adapter now reads the sent copy back from the destination chat and returns its real id.

Recovery is best-effort: the forward already succeeded, so any error reading it back never fails the operation, and when the copy cannot be identified an empty id is returned so the row's waMessageId is left unset (no ack can mis-match it) — never a synthetic or cross-matching source id.
rmyndharis added a commit that referenced this pull request Jun 19, 2026
* fix(webhook): deliver session lifecycle events and key webhook hardening (#335)

* fix(security): pin outbound webhook and media fetches to validated IP (#338)

* fix(plugins): persist plugin enable/config and restore (#339)

* fix(message): persist bulk-sent messages, sanitize SSRF (#340)

* fix(engine): return the real id for forwarded messages (#341)

* fix(security): harden outbound requests, IPv6 SSRF (#344)

* fix(security): secret-file perms, key pepper, allowedIps (#345)

* fix(storage): bound tar imports, contain storage keys (#346)

* fix(session): reconcile late acks, serialize reactions (#348)

* fix(contract): webhook timeout, bounded shutdown, 501 (#350)

* feat(session): force-kill a stuck session (#352)

* merge #343

* merge #351

* chore(release): v0.4.3 — CHANGELOG, version bump (package.json/dashboard/swagger), README + docs
@rmyndharis

Copy link
Copy Markdown
Owner Author

Shipped in v0.4.3 (integrated via the release PR #354 and tagged v0.4.3). Thanks! 🎉

@rmyndharis rmyndharis closed this Jun 19, 2026
@rmyndharis rmyndharis deleted the fix/wwjs-forward-message-id branch June 19, 2026 18:33
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.

1 participant