Summary
In messageHandle, the loop over received.statuses uses return where it should use continue. WhatsApp Cloud API delivers status updates in batches, so a single item that fails a guard aborts the remaining items in the same webhook payload — silently, with a 200 returned to Meta.
This is distinct from #2573 (the contacts[0].profile.name TypeError). That one prevents the block from being reached at all; this one drops siblings once it is reached. It survives on develop, so it is not fixed by #2514.
Affected code
src/api/integrations/channel/meta/whatsapp.business.service.ts
if (received.statuses) {
for await (const item of received.statuses) {
const key = { id: item.id, remoteJid: this.phoneNumber, fromMe: ... };
if (settings?.groups_ignore && key.remoteJid.includes('@g.us')) {
return; // <-- aborts the whole batch
}
if (key.remoteJid !== 'status@broadcast' && !key?.remoteJid?.match(/(:\d+)/)) {
const findMessage = await this.prismaRepository.message.findFirst({ ... });
if (!findMessage) {
return; // <-- aborts the whole batch
}
Why it matters in practice
The !findMessage case is not exotic — it happens for any message this Evolution instance did not send itself:
- messages sent directly through the Graph API
- messages sent from the WhatsApp Business app on the phone
- messages predating the instance, or sent while the DB was being migrated
Meta commonly batches statuses for several messages into one payload. One such
"foreign" wamid arriving first means every other message in that batch never
gets its MESSAGES_UPDATE and never gets a MessageUpdate row. Delivery and
read receipts go missing for messages that Evolution does own, with nothing
in the logs to explain it.
Expected
Skip the offending item, keep processing the rest of the batch.
Suggested fix
in both places inside the for await (const item of received.statuses) loop.
Note that continue is also the correct semantics for groups_ignore: the
setting means "ignore group messages", not "stop processing this payload".
Versions checked
| version |
affected |
| v2.3.7 (latest stable) |
yes |
main |
yes |
| v2.4.0-rc2 |
yes |
develop |
yes — #2514 does not touch this loop |
Environment
- Evolution API 2.3.7,
WHATSAPP-BUSINESS (Cloud API) integration
- Node v20.20.0, PostgreSQL, PM2
Summary
In
messageHandle, the loop overreceived.statusesusesreturnwhere it should usecontinue. WhatsApp Cloud API delivers status updates in batches, so a single item that fails a guard aborts the remaining items in the same webhook payload — silently, with a200returned to Meta.This is distinct from #2573 (the
contacts[0].profile.nameTypeError). That one prevents the block from being reached at all; this one drops siblings once it is reached. It survives ondevelop, so it is not fixed by #2514.Affected code
src/api/integrations/channel/meta/whatsapp.business.service.tsWhy it matters in practice
The
!findMessagecase is not exotic — it happens for any message this Evolution instance did not send itself:Meta commonly batches statuses for several messages into one payload. One such
"foreign" wamid arriving first means every other message in that batch never
gets its
MESSAGES_UPDATEand never gets aMessageUpdaterow. Delivery andread receipts go missing for messages that Evolution does own, with nothing
in the logs to explain it.
Expected
Skip the offending item, keep processing the rest of the batch.
Suggested fix
in both places inside the
for await (const item of received.statuses)loop.Note that
continueis also the correct semantics forgroups_ignore: thesetting means "ignore group messages", not "stop processing this payload".
Versions checked
maindevelopEnvironment
WHATSAPP-BUSINESS(Cloud API) integration