Repeat Without Memory: How n8n Creates CRM Task Duplicates

Learn how failed n8n workflows create duplicate CRM tasks and how atomic claims, event keys, and pre-retry checks prevent them.

  • A failure that is invisible in the log
  • Atomic claim before the action
  • The hardest case: interruption between success and recording the result
  • What This Means for Business

Key point

Several discussions in the n8n community converged on the same failure. The workflow reports an error even though the action has already been completed in the external system, and a rerun creates a second CRM task. A retry is safe when it knows what has already happened. Without that knowledge, other reliability measures—alerts, retries, and monitoring—cannot prevent duplicates.

A failure that is invisible in the log

  1. The author of one demo describes the situation as follows.

  2. The customer request reaches the CRM, but the response does not return from the CRM. The workflow is marked as failed.

  3. The team must determine whether a follow-up already exists before starting the process again.

  4. If something goes wrong, there are two possible outcomes: the customer is lost, or two managers call them about the same issue. In the demo, the author deliberately loses the response after creating the task.

  5. The operator gets a recovery action that finds the existing task.

  6. The original delivery is then replayed, and the result remains the same: one task assigned to Sales.

  7. The boundary is clear: the error occurred after the side effect, but the execution is considered unsuccessful. The “it failed, so we’ll run it again” pattern

  8. creates a duplicate at this point.

Atomic claim before the action

Another participant explained how to build protection in n8n, using the following sequence.

First, a stable event key is calculated: a hash of the source and the event’s external identifier (`source + externalEventId`). The key is normalized using lowercase text, trimmed spaces, and a canonical time zone for all timestamps.

The Postgres node then executes `INSERT INTO event_claims(event_key, status, claimed_at) VALUES (...) ON CONFLICT DO NOTHING RETURNING event_key`.

If the result is empty, the event has already been claimed by another execution, so the current execution does not launch the action. The database provides atomicity: two parallel executions cannot insert the same row simultaneously. A separate “did this event already occur?” query before insertion provides no such guarantee: another execution can slip in between the check and the write. Key normalization is also important.

The same address with different capitalization or the same timestamp in different time zones produces two different hashes, and the protection silently stops working.

Map out your integration landscape

The hardest case: interruption between success and recording the result

  1. Participants agreed that the most damaging interruption occurs after a successful external action but before completion is recorded. The claim is already present, the status remains “in progress,” and the CRM task has already been created. A claim records only the intention to perform an action; it says nothing about the result.

  2. That is why a retry must first check the external system: find the task by its event key and, if it exists, mark the record as completed.

  3. That is exactly what “recovery” does in the demo.

  4. Combining the two approaches into one pattern is our interpretation: each author describes only part of it.

  5. For a CRM where tasks can be searched by an external identifier, the pattern works directly.

  6. If the system does not support this kind of search, the pattern must be extended—for example, by writing the event key to a task field when the task is created.

What This Means for Business

  1. A duplicate CRM task seems minor until it turns into two calls to a customer, a double invoice, or a double charge.

  2. The cost of an error is determined by what lies beyond the side effect: money, the customer, or reputation. n8n itself does not control that cost. There is also a market signal.

  3. The same forum threads are filled with freelancers offering deduplication, error handling, and follow-up scenarios as separate services.

  4. Demand exists because without these mechanisms, automation appears to work until the first network failure.

  5. The n8n 1.123.83 patch pins `cjs-module-lexer` version 2.2.0 following the review.

  6. This is routine platform maintenance and has nothing to do with idempotency.

  7. The platform is updated regularly, while the person designing the process is responsible for retry correctness.

How we approach this in integrations

  1. In [AI-native integration](/), we build in idempotency from the start because time to outcome (TTU) depends on it.

  2. The seemingly simple pattern “request received, task created”

  3. requires stable event keys, an event-claims table, verification against the external system, and a clear operator screen.

  4. The same principle applies at another scale: an Apache Kafka consumer with “at least once” semantics or a MuleSoft-level bus produces duplicates by design, making event-key deduplication essential.

  5. Another practical rule came from a related discussion.

  6. Its author recommended splitting one large workflow into three smaller ones: onboarding, the daily plan, and incoming message intake.

  7. For retries, this pays off twice: the “before the side effect” boundary

  8. and the “after” stage is easier to test and fix in a small scenario.

Verdict

Before adding another AI branch to the workflow, check one thing: what happens if execution is interrupted immediately after a successful call to the external system? If the answer is “we don’t know” or “it will create a duplicate,” the automation is not production-ready, and it is too early to add new capabilities. A leader credits the result to the process that survives its own failure.

Discuss the article: Retry Without Memory: How n8n Automation…

Enter your email or phone number so we can get back to you.

Send via: