-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
When syncFullHistory is enabled, Chatwoot historical message import fails to find messages from contacts using LID (Linked Identity Device) addressing, even though these messages exist in the database.
Impact
- Priority: P1 - High
- Messages visible in WhatsApp Web are NOT synced to Chatwoot
- Customer service agents cannot see complete conversation history
- 8 instances affected, 942 unsynced LID messages across all instances
- ~5-15% of contacts affected (WhatsApp multi-device users)
Affected Instances (Production Data 2026-01-30)
| Instance | LID Messages (30d) | Not Synced | Unique LID Contacts |
|---|---|---|---|
| Mama First (6287792348908) | 14,207 | 486 | 1,374 |
| Mama First (6287844135577) | 1,303 | 155 | 99 |
| Theory of Living | 202 | 202 (ALL) | 31 |
| Indorama (3 instances) | ~16,000+ | 82 | 1,287 |
| Widget Works (2 instances) | 19 | 5 | 13 |
Root Cause
File: src/api/integrations/chatbot/chatwoot/utils/chatwoot-import-helper.ts:456
Function: createMessagesMapByPhoneNumber()
During historical sync (messages.set), Baileys provides stripped message keys containing only {id, fromMe, remoteJid}. No remoteJidAlt, no senderPn, no addressingMode — these fields are undefined during historical sync.
A prior fix (commit 630f5c56, July 2025) attempted to normalize LID using senderPn, but this field is not available in stripped keys, making the fix ineffective.
Why Real-Time Works But Historical Doesn't:
| Flow | remoteJidAlt available? | LID resolved? | Result |
|---|---|---|---|
Real-time (messages.upsert) |
YES | YES (line 1518) | Messages import correctly |
Historical (messages.set) |
NO (stripped keys) | NO | Messages missed |
IsOnWhatsapp Mapping: The IsOnWhatsapp table stores LID-to-phone mappings, but only for contacts with prior real-time messages. Only 15% (142/942) of unsynced messages are resolvable via existing mappings.
Distinction from Previous LID Issues
This is DIFFERENT from the LID duplicate conversation issue (RESOLVED in v2.3.7):
- Previous issue (RESOLVED): Real-time sync creating duplicates — Fixed with OnWhatsappCache
- Current issue (ACTIVE): Historical import (
messages.set) not resolving LID to phone
Backfill Status: ✅ COMPLETED (2026-01-30)
All 942 unsynced LID messages have been backfilled to Chatwoot using scripts/backfill-lid-to-chatwoot.ts.
Results
| Metric | Value |
|---|---|
| Messages imported | 670 |
| Messages already existed (skipped) | 748 |
| Errors | 0 |
| Instances processed | 8/8 |
Execution Phases
- Sample test: 2 messages for single LID contact → verified in Chatwoot UI
- Mama First (6287792348908): 435 imported, 50 skipped, 0 errors
- All remaining instances: 235 imported, 698 skipped, 0 errors
Issues Found & Fixed During Backfill
-
"Você" contact names — 62 contacts created with name "Você" (the instance's WhatsApp name from outgoing
pushName). Fixed viascripts/fix-voce-contacts.ts— 60 got real names, 2 fell back to LID number. -
Multiple LIDs per person — Same physical person can have multiple LID identifiers across devices/sessions, creating duplicate Chatwoot contacts. Cannot be fixed in backfill (no mapping). Self-healing at
chatwoot.service.ts:644-666will auto-merge when real-time messages arrive. -
Dry-run bug — Initial dry run created real contacts/conversations (23 orphaned empty conversations). Fixed DRY_RUN guard in script. Cleaned up via
scripts/cleanup-orphaned-conversations.ts.
Remaining: Code Fix (Parts 1-2)
The backfill resolved the existing data gap. The code fix is still needed to prevent this from recurring on future reconnects.
Part 1: Resolve LID in messages.set Handler
File: src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Location: messages.set handler, before prepareMessage() call (~line 1045)
Before processing messages in messages.set, batch-resolve all LID JIDs using IsOnWhatsapp table. For resolvable LIDs (~15%), replace remoteJid with the phone number. For unresolvable LIDs, keep the @lid identifier as-is and let it pass through to Chatwoot.
Key implementation detail: Use prismaRepository.isOnWhatsapp.findMany() with jidOptions: { contains: lid } to batch-resolve, then replace m.key.remoteJid before prepareMessage().
Part 2: Allow Unresolved LID Through to Chatwoot (Do NOT Skip)
Do NOT add @lid to isIgnorePhoneNumber() in chatwoot-import-helper.ts:566. Let unresolved LID messages pass through the normal import flow. This creates a temporary LID contact in Chatwoot.
Self-healing (existing code, no changes needed): chatwoot.service.ts:644-666 automatically updates the LID identifier to real phone or merges contacts when real-time messages arrive. Conversations linked by contact_id (integer FK), not identifier string — no duplicates created.
Key Context for Implementation
- Prior attempted fix (commit
630f5c56): Usedm.key.senderPnbutsenderPnis undefined in stripped keys duringmessages.set. The new fix usesIsOnWhatsapplookup instead. - Real-time normalization works at
baileys.service.ts:1518-1519usingremoteJidAlt— this is the pattern to match for historical sync. participantAltis NULL in all stored LID messages — the phone number is only available in-memory during real-time processing, not stored in DB.- Also fix:
jidOptionsdouble-domain bug inonWhatsappCache.ts—getAvailableNumbers()appends@s.whatsapp.netto JIDs that already include the domain.
Scripts & Documentation
| Script | Purpose |
|---|---|
scripts/backfill-lid-to-chatwoot.ts |
Main backfill (imports unsynced LID messages) |
scripts/fix-voce-contacts.ts |
Fix "Você" contact names |
scripts/cleanup-orphaned-conversations.ts |
Cleanup orphaned data from dry-run bug |
scripts/lid-phone-mapping-check.sql |
IsOnWhatsapp mapping analysis |
scripts/backfill-lid-messages.sql |
Impact assessment queries |
docs/troubleshooting/30-01-26-chatwoot-syncfullhistory-lid-missing.md |
Full investigation & execution log |
Action Items
✅ Completed
- Identify root cause and exact bug location
- Quantify impact across all instances
- Investigate IsOnWhatsapp mapping availability (15% resolvable)
- Verify Chatwoot self-healing for LID contacts
- Confirm no duplicate conversations
- Document findings and fix proposal
- Backfill all 8 instances — 670 messages imported, 0 errors
- Fix "Você" contact names — 62 contacts fixed
- Cleanup orphaned data from dry-run bug
🔲 Pending (Code Fix)
- Create feature branch and implement fix (Parts 1-2)
- Fix
jidOptionsdouble-domain bug inonWhatsappCache.ts - Deploy to production
- Verify fix works on next reconnect
- Update CHANGELOG
Reported: 2026-01-30
Backfill Completed: 2026-01-30
Affected Instances: 8 (Mama First, Theory of Living, Indorama, Widget Works)
Component: Chatwoot Integration / Historical Sync
Priority: P1 - High