[BUG] Cloud API: a single unknown wamid in a `statuses` batch silently drops the whole batch (`return` instead of `continue`)

Open Beginner friendly
#2,700 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
1/5
Estimated time
Under an hour
Newbie friendliness
88/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
api, backend

Research direction

Start in src/api/integrations/channel/meta/whatsapp.business.service.ts at the for-await loop over received.statuses in messageHandle. Check both guards that currently return, then verify that skipping one status still allows later statuses in the same webhook batch to be processed. Done means foreign or ignored items no longer abort sibling status updates.

Written by the indexing model from the issue text.

Description

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
-            return;
+            continue;

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
Dominant language
TypeScript
Stars
9.6k
Forks
7.3k
PR merge metrics
No merged PRs in 30d

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from evolution-foundation/evolution-api

All issues in evolution-foundation/evolution-api

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.