[BUG] Chatwoot integration duplicates messages when a device re-delivers the same key.id — getExistingSourceIds exists but is never called on the live path

Aperta Adatta ai principianti
#2,675 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
76/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Tranquilla
Stack tecnologico
postgresql, typescript
Ambito
api, backend

Direzione di ricerca

Inizia leggendo ChatwootService.createMessage e confronta il suo percorso live con ChatwootImport.getExistingSourceIds e importHistoryMessages. Segui come vengono passati source_id e conversationId, quindi verifica che gli arrivi ripetuti di WAID:<key.id> vengano ignorati, mentre gli errori di ricerca consentano comunque alla consegna di continuare. Conferma che i chiamanti esistenti gestiscano il risultato null come descritto.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

📋 Bug Description

When a sender's device re-delivers the same WhatsApp message (identical key.id, new timestamp — e.g. a buggy device or an unofficial client stuck in a loop resending an auto-reply), the Chatwoot integration creates a new Chatwoot message on every arrival. There is no idempotency check on the live path.

Real-world impact (production, v2.3.7): one guest's device looped an away-message roughly once a minute. In ~25h we accumulated 837 copies of a single message in one Chatwoot conversation (and a second looping key.id later reached 539 copies). The conversation became unusable for the support team. WhatsApp mobile shows the message once (native dedup by key.id); Chatwoot shows every copy.

The interesting part: the codebase already contains exactly the right checkChatwootImport.getExistingSourceIds(sourceIds, conversationId) queries Chatwoot's messages.source_id for WAID:<key.id> — but it is only called from the history import path (importHistoryMessages). The live path (ChatwootService.createMessage) posts to Chatwoot with source_id: WAID:<key.id> without consulting anything.

🔄 Steps to Reproduce

  1. Evolution API v2.3.7 (baileys channel) + Chatwoot integration enabled.
  2. From a sender device, deliver the same message twice with the same key.id (a looping unofficial client does this naturally; the events arrive with status: DELIVERY_ACK, source: 'unknown' and a fresh messageTimestamp each time).
  3. Watch the Chatwoot conversation.

✅ Expected Behavior

Second and subsequent arrivals of an already-imported key.id for the same conversation should be ignored (the same way importHistoryMessages already filters via getExistingSourceIds), or at least be configurable to be ignored.

❌ Actual Behavior

Every arrival creates a new Chatwoot message with the same source_id (WAID:<key.id>). messages.source_id in Chatwoot has a non-unique index, so nothing stops the duplicates downstream either.

💡 Suggested Fix

Call the existing check in the live path. We are running this in production (patched into createMessage) and it fully stopped the flood without affecting legitimate traffic:

// at the top of ChatwootService.createMessage(...), sourceId = "WAID:" + key.id
if (sourceId) {
  try {
    const existing = await chatwootImport.getExistingSourceIds([sourceId], conversationId);
    if (existing.has(sourceId)) {
      this.logger.warn(`[dedup] repeated message ignored source_id=${sourceId} conversation_id=${conversationId}`);
      return null; // callers already handle the null ("message not sent") path
    }
  } catch (e) {
    this.logger.warn(`[dedup] check unavailable: ${e}`); // fail open
  }
}

Notes:

  • getExistingSourceIds already accepts the optional conversationId argument, so the lookup is cheap (indexed on source_id).
  • Failing open on lookup errors keeps message delivery safe if the Chatwoot DB connection blips.
  • Verified in production: 14 duplicate arrivals blocked in the first minutes across 2 looping key.ids, zero legitimate messages affected.

🌍 Environment

  • Evolution API: v2.3.7 (image evoapicloud/evolution-api:v2.3.7)
  • Connection type: baileys
  • Chatwoot: v4.16.1, integration via CHATWOOT_ENABLED=true
  • DB: PostgreSQL (shared instance for Evolution + Chatwoot import connection)
  • OS: Linux (Docker)
Lingua principale
TypeScript
Stelle
9.6k
Fork
7.3k
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di evolution-foundation/evolution-api

Tutte le issue di evolution-foundation/evolution-api

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.