At a Glance — Race Conditions in n8n Agent Workflows

  • The pattern that breaks: check shared state (a calendar, stock count, CRM record), then act on it — with nothing stopping a second execution from checking in between
  • Why AI makes it worse: an agent that reasons for several seconds between "check" and "act" stretches the danger window from milliseconds to seconds
  • Why it's not rare: n8n runs each webhook call as its own execution, webhook senders resend, Retry On Fail re-runs nodes, and agents sometimes call the same tool twice
  • The fix: claim before you act (in a store that refuses a second claim), give every business action an idempotency key, and re-check the real system right before the final write
  • What doesn't fix it: a better prompt, a stricter model, or n8n queue mode — queue mode adds parallelism, so it makes races more likely

Why this keeps happening

A popular n8n appointment-booking workflow shared on LinkedIn this month drew the same comment from at least seven different engineers: what happens when two people ask for the same slot at once? The answer, in almost every check-then-act workflow, is that both get it.

n8n runs every incoming request as its own execution, and executions run in parallel. Execution A reads the calendar: 3pm free. Execution B reads the calendar: 3pm free. A books 3pm. B books 3pm. Each step did exactly what it was built to do — the failure lives in the gap between them, which is why it never shows up in testing, where requests arrive one at a time.

Why the AI step makes it worse

In a plain workflow, check and act might sit a few hundred milliseconds apart. Put an AI Agent node between them — reading the request, deciding which slot fits, calling a tool, maybe confirming with the user — and that gap grows to several seconds, sometimes much longer when there's a conversation in between. The probability of a collision grows with that window. An agent that works flawlessly in a demo can double-book within its first busy hour.

Agents also add their own duplicates: a model may call the same booking tool twice in one run, or a timeout makes the workflow retry a call that actually succeeded. Neither is the model "making a mistake" in a way a better prompt fixes — they're ordinary distributed-systems problems arriving through a new door.

Where duplicate and parallel runs come from

The fix: claim first, key every action, re-check before writing

1. Claim the resource before acting on it

Instead of "check, then book", the workflow first tries to claim the slot in a store that refuses a second claim. Only the execution that wins the claim continues. In Postgres that's a single insert against a unique constraint:

INSERT INTO slot_claims (slot_id, execution_id)
VALUES ('2026-10-08T15:00', '{{ $execution.id }}')
ON CONFLICT (slot_id) DO NOTHING
RETURNING slot_id;

If a row comes back, this execution owns the slot. If nothing comes back, someone else got there first — route to a clean "that time was just taken" response. A Redis key set only if it doesn't already exist does the same job. What matters is that the database or Redis makes the decision atomically, not an IF node comparing two values that may already be stale.

2. Give every business action an idempotency key

Build one ID per real-world action — the booking request ID, the order ID, the webhook event ID — record it before the side effect, and check it first on every attempt. When the webhook resends, the retry fires, or the agent calls the tool again, the second attempt sees the key is already done and stops instead of booking or charging twice. Where the downstream API accepts an idempotency key of its own (Stripe does), pass it through as well.

3. Re-check the real system right before the final write

Your claim table protects against other runs of this workflow. It doesn't know about someone booking the same slot directly in the calendar app. A last read immediately before the write — and a clear failure path if the slot is gone — covers what the claim can't.

Let the agent decide, not commit

The cleanest structure keeps the AI out of the critical section entirely: the agent figures out what the user wants, then hands a structured request to a plain, deterministic sub-workflow that does claim → re-check → book. The slow, unpredictable part stays outside the window where races happen.

How to test for it before customers do

Fire the same request at the webhook twenty times at once — a short script or a load-testing tool does it in seconds — and count the bookings. One is the right answer. Then resend a single webhook event three times and check that nothing happens twice. Both tests take minutes and catch the failure that ordinary click-through testing never will.

Need This Built?

Entech Solutions builds n8n agent workflows that hold up under real traffic — claim-first concurrency, idempotent side effects, and load tests before launch. See our n8n AI & Agentic Workflow Design page, our guide to n8n error handling, or get in touch to review a workflow you already run.