Your agent ran twice. The client got two invoices, two welcome emails, and one very direct phone call. Nothing errored out. That is the part that stings.

AI agent duplicate actions are repeated real world side effects, like a second email or a second charge, caused by the same job running more than once. They are not a model quality problem. They are a plumbing problem, and plumbing is fixable.

I spent 16 years building enterprise automation before I built anything for my own clients, and the double send was the failure I saw most often in production. The fix is boring, mechanical, and it works every time. I call it the ONCE Check.

Key takeaways

  • AI agent duplicate actions happen when a retry, a timeout, or a re-run repeats a step that already changed something outside the agent.
  • An idempotent action is one that produces the same end state whether it runs once or five times, which is the property you are actually trying to build.
  • The ONCE Check is four steps: One key per job, Note the key before you act, Check the ledger before you repeat, Expire the key on purpose.
  • Stripe and Resend both accept an Idempotency-Key header and both keep that key for 24 hours, so a retry inside that window returns the original response instead of repeating the work.
  • n8n ships a Remove Duplicates node with a Remove Items Processed in Previous Executions operation, and Zapier dedupes polling triggers on the item’s primary key, which defaults to the field named id.

Why AI agent duplicate actions happen

An agent is a loop. It reads a situation, picks a tool, calls it, reads the result, and decides what to do next. Every one of those tool calls can fail in a way that looks identical to success from the agent’s side.

  1. The timeout lie. The agent calls an email API, the connection drops before the response comes back, and the email was already sent. The agent sees a failure and tries again.
  2. The blind retry. Your platform retries a failed step automatically. If step three of five sent the invoice and step four crashed, a retry from the top sends the invoice again.
  3. The polling overlap. A trigger checks a source every few minutes. If the run takes longer than the interval, two runs pick up the same record.
  4. The human re-run. Somebody looks at a run that appears stuck and hits execute again. This one is the most common of all, and it is nobody’s fault if the system allows it.

Notice what all four share. The agent never knows it already did the work. It has no memory of the side effect, only of the conversation. Good AI agent error handling catches the error. It does not, by itself, stop the repeat.

The ONCE Check: four steps that make a job unrepeatable

The goal is not to stop retries. Retries are how automation survives a flaky network. The goal is to make a retry harmless. That is what idempotent automation means, and you get there in four moves.

One key per job

Before the agent acts, generate a string that identifies this specific unit of work. Not the run, the work. “Send the welcome email to customer 4471” is one job, no matter how many times the workflow executes.

Build the key from stable parts: the action name plus the record id, like welcome-email/4471. Stripe suggests a version 4 UUID and allows keys up to 255 characters. Resend allows up to 256 and suggests the same action plus entity id pattern. Never build a key from a timestamp. A timestamp makes every attempt look like new work, which is the problem you are solving.

Note the key before you act

Write the key to a ledger, then perform the action. A ledger is just a table of keys the system has already claimed. An Airtable base, a Postgres table, a Google Sheet, or n8n’s own deduplication store all work.

Write the key first, even though it feels backwards, because a key written after the action does nothing when the step dies mid flight. If the action then fails for real, you mark that row failed and let your retry logic clear it. A false block you can see and fix beats a duplicate charge you find out about from the client.

Check the ledger before you repeat

Make the lookup the first step of the job, not a safety net at the end. If the key is already in the ledger and marked complete, exit and log a skip. The run should end green, not red. A skipped duplicate is a success.

Log every skip with the key and timestamp, in the same place as the rest of your AI agent audit trail, because a client asking “did it send twice” deserves a yes or no, not a guess.

Expire the key on purpose

A ledger that never forgets eventually blocks work it should allow. The customer who signed up in March and signed up again in October is not a duplicate.

So pick a window and write it down. The API vendors picked theirs: Stripe’s documentation says keys can be removed automatically once they are at least 24 hours old, and Resend states plainly that keys are kept for 24 hours. For a daily job, 24 hours is a sane default. For a monthly report, use the month in the key itself and let the window be the month.

Example scenario: the welcome email that sent three times

Example scenario, not a client result. A one person agency runs an onboarding agent. New row in the CRM, the agent drafts a welcome email, sends it, creates a folder, and posts a summary to Slack.

Tuesday, the Slack step fails because a token expired. The platform retries the whole workflow twice. The email goes out three times. The folder is created three times. Slack still never gets the summary, and nobody notices until the client replies “why do I have three of these.”

With the ONCE Check applied, the second run builds the same key, onboard/crm-4471, finds it marked complete, and exits in under a second. The email sends once. The folder is created once. The Slack failure is still a failure, and now it is the only thing in the error log, which means you fix the actual problem on Tuesday instead of apologizing on Wednesday.

What your tools already do for you

You do not have to build all of this from scratch. Check what the stack handles before you write a line of logic.

  • Payments and email. Stripe accepts an Idempotency-Key header on POST requests and returns the saved response from the first request when you retry with the same key. Resend works the same way through its own Idempotency-Key header, and reusing a key with a different payload returns a 409 error rather than quietly sending something new.
  • n8n. The Remove Duplicates node has a Remove Items Processed in Previous Executions operation. Set Keep Items Where to Value Is New and it compares against a stored history, 10,000 items by default. There is also a Clear Deduplication History operation for when you need to reset it during testing.
  • Zapier. Polling triggers dedupe on a primary key, which defaults to the field named id, and Zapier caches the ids it has seen. Two caveats: the cached list clears when the Zap is turned off, and only the first page of trigger results is checked.
  • Your own API calls. Anything you hit with a plain HTTP node is on you. That is where the ledger earns its keep.

Platform level deduplication covers the trigger. It does not cover an agent that decides to call the same tool twice inside one run. That part is design, and it pairs with clear AI agent escalation rules so the agent asks instead of guessing when the ledger is ambiguous.

Action steps for this week

  1. List every step in your agent that changes something outside itself: sends, charges, posts, creates, deletes. That list is your exposure.
  2. For each one, write the key format on paper first. Action name plus record id. If you cannot name a stable id, you have found a design problem, not a coding problem.
  3. Create the ledger. One table, four columns: key, status, created time, last error. Do not over build it.
  4. Add the lookup as step one and the write as step two, ahead of the action.
  5. Test the ugly way. Run the job, kill it mid action, run it again. If the side effect happens twice, you are not done.
  6. Set the expiry window and document it next to your AI agent rollback plan, since both get used on the same bad day.

On a live workflow, watch it before you trust it. Running the agent in shadow mode for a few days shows how often the ledger actually catches something, usually more often than anyone expects.

Frequently asked questions

What are AI agent duplicate actions?

They are repeated side effects outside the agent, such as a second email, charge, or record, caused by the same job executing more than once. The agent is working correctly in each run. The system simply never told it the work was already done.

Why does retrying an AI agent create duplicates?

Because a retry usually restarts the job, not the failed step. Any action that already completed runs a second time, and the agent has no memory of the first attempt’s effects on the outside world.

How long should an idempotency key last?

Match the window to how often the same work can legitimately repeat. Stripe and Resend both use 24 hours for their own keys, which is a reasonable default for daily workflows, while monthly jobs are better served by putting the period into the key itself.

Can I just check whether the record already exists instead?

Sometimes, and when you can, do it. That works when the action creates a record you can query, such as a CRM row. It fails for actions that leave nothing behind to look up, like a sent email or a posted message, which is exactly where a key and a ledger are required.

Does n8n stop duplicate agent actions automatically?

Only for items you route through the Remove Duplicates node. It has no view into what a tool call did outside the workflow, so a duplicate send inside a single execution still needs your own key and ledger.

To recap

AI agent duplicate actions come from retries, timeouts, overlapping polls, and well meaning humans, and none of those are going away. You are not trying to prevent the second attempt. You are trying to make the second attempt do nothing.

The ONCE Check gets you there: One key per job, Note the key before you act, Check the ledger before you repeat, Expire the key on purpose. Use the idempotency support your payment and email providers already give you, lean on the deduplication nodes in your automation platform for triggers, and cover the rest with a four column table.

My Army background was 25U Signal Support Systems Specialist, which is a job built on one idea: the message gets through exactly once, intact, or it did not get through at all. Agents are the same discipline with better tooling. Build the ledger before you need it, and the double send stops being a story you have to apologize for.

If you build AI agents for your own business or for clients, subscribe to the blog. One system breakdown like this lands here every day.

References

n8n. (n.d.). Remove Duplicates node. n8n Docs. Retrieved October 20, 2026, from https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.removeduplicates/

Resend. (n.d.). Idempotency keys. Resend Docs. Retrieved October 20, 2026, from https://resend.com/docs/dashboard/emails/idempotency-keys

Stripe. (n.d.). Idempotent requests. Stripe API Reference. Retrieved October 20, 2026, from https://docs.stripe.com/api/idempotent_requests

Zapier. (n.d.). How deduplication works in Zapier. Zapier Platform Documentation. Retrieved October 20, 2026, from https://docs.zapier.com/integrations/build/deduplication


Discover more from Corran Force Designs

Subscribe to get the latest posts sent to your email.

Leave a Reply

Discover more from Corran Force Designs

Subscribe now to keep reading and get access to the full archive.

Continue reading