The Duplicate Welcome Email
A retailer builds a welcome journey triggered by the accountCreated event. The event fires from two systems: the website (immediately after signup) and a nightly CRM sync that re-sends the same event with the same customerId for every account created that day. The journey has a 10-minute wait, then an email, then a 2-day wait, then a second email. Within a week, 18% of new accounts receive the welcome email twice, and some receive the second email 2 days after the duplicate first email rather than the original. The team's first instinct is to add a condition node checking whether the profile already has a welcomeSent flag, but the flag is written by a downstream system that lags by up to 30 minutes.
1. What is the root cause of the duplicate sends, and why will the proposed `welcomeSent` condition node not reliably fix it?
Read the worked answer
The root cause is that the same entry event is delivered twice with the same identity, and the journey has no entry-suppression mechanism. Two independent problems compound:
- No re-entry control. By default a profile can re-enter a journey each time the qualifying event arrives. The nightly CRM sync is a second, redundant source of the same logical event.
- Event de-duplication is not happening at the source. The website and CRM both emit
accountCreated; nothing distinguishes them or collapses them.
The welcomeSent flag approach fails for two reasons:
- Timing. The flag lags up to 30 minutes, but the journey's first wait is only 10 minutes. The condition would be evaluated before the flag exists, so both runs pass.
- Placement. A condition node suppresses the message, not the journey execution. The duplicate path still consumes the 2-day wait and the second email, so the symptom (second email arriving relative to the duplicate) persists.
Fix direction: de-duplicate at ingestion (single authoritative event source, or an idempotency key), and/or use journey re-entry settings to prevent a profile from re-entering while already in the journey.
2. The team wants to keep both event sources for resilience. Propose a design that tolerates the duplicate event without relying on a lagging flag.
Read the worked answer
Decouple event receipt from journey entry using a guard the journey can evaluate synchronously at entry:
- Normalize at ingestion. Tag each incoming event with a source and an idempotency key (e.g.,
customerId + accountCreated). Drop exact duplicates before they reach the journey. - Use re-entry control as the primary guard. Configure the journey so a profile cannot re-enter while an instance is active. The nightly duplicate then finds the profile already in-flight and is ignored - no flag needed, no lag.
- Make the wait tolerant. If a short delay is desired, keep it, but do not rely on downstream state written after the wait.
- Verify with a test profile. Send the event twice within seconds and confirm only one instance exists.
Key judgement: the guard must be synchronous with entry and journey-level, not a downstream message-level condition.