Idempotency in Agent Actions: Safe to Repeat by Design
AI Agents

Idempotency in Agent Actions: Safe to Repeat by Design

Agents retry, resume and duplicate calls constantly. Idempotency keys, natural keys and check-then-act patterns that stop one action happening three times.

An agent calls the refund endpoint. The response times out. The agent, seeing no confirmation, calls it again. The customer receives two refunds, and the trace shows a well-behaved agent doing exactly what any careful actor would do with incomplete information.

This is not an edge case in agent systems, it is the default. Agents retry on ambiguity, resume from checkpoints, get restarted mid-run, and occasionally re-derive the same plan after a context reset. Every one of those paths can re-issue an action that already happened.

Idempotency — the property that doing something twice has the same effect as doing it once — is the cheapest insurance available here, and it has to be built into the tools rather than prompted into the agent.

Why agents duplicate more than ordinary clients

A conventional client retries when the network fails. An agent retries for that reason and several others.

It retries because a tool response was ambiguous and it could not tell success from failure. It re-derives an action after its context was compacted and the record of having done it was compressed away. It resumes from a checkpoint written before the action completed. And in a multi-agent system, two workers with overlapping briefs can each decide the same action is needed, neither aware of the other.

That last case is worth dwelling on, because no amount of retry logic addresses it. It is a coordination failure, and the only defence at the tool layer is making the second call a no-op — which is what idempotency gives you.

Idempotency keys

The standard mechanism: the caller generates a unique key per logical operation and sends it with the request. The server records the key with the result. A second request bearing the same key returns the stored result instead of executing again.

The subtlety with agents is where the key comes from. If the agent generates a random key per attempt, every retry gets a fresh key and the protection does nothing. The key must be derived from the intent — the operation plus its identifying arguments — so that two attempts at the same logical action produce the same key.

Better still, do not let the model choose. Have the tool layer compute the key by hashing the normalised arguments, so idempotency is a property of the infrastructure rather than something the agent has to remember. Anything you rely on the model to remember will eventually be compacted away, for the reasons set out in agent memory and context management.

Give keys a retention window long enough to cover the slowest legitimate retry, including a resumed run. A window of minutes will not protect a run that resumes an hour later.

Natural keys are better than generated ones

Where the domain supplies a unique identifier, use it and skip the key machinery entirely.

Creating a ticket for issue 4417 is naturally idempotent if the ticket has a unique constraint on the issue reference. Assigning a label, setting a status, adding a member to a group — these are set operations, and set operations are inherently safe to repeat.

Prefer this framing when you design tools for agents. A tool called set_status is safe to call twice; a tool called advance_status is not. The same work can very often be expressed either way, and expressing it declaratively removes the whole problem rather than managing it. It is one of the most valuable habits in tool schema design.

Check-then-act, and why it is not enough

The intuitive defence is to have the agent check before acting: look for an existing refund, and only create one if none is found.

This narrows the window and does not close it. Between the check and the action, another worker can act, and in a fan-out that is precisely what happens. Check-then-act is a race condition with a model in the middle of it, and models are slow, which makes the window unusually wide.

Use it as a cost optimisation — it avoids pointless calls — but never as the correctness mechanism. Correctness belongs at the point of mutation, in a unique constraint, a conditional write or a compare-and-set. That is also the only defence that holds when two agents run concurrently against the same resource.

Make tool responses unambiguous

Half of all duplicate actions trace back to a response the agent could not interpret. A timeout, an empty body, a 500 after the write committed — the agent genuinely does not know whether the action happened.

Tools should say what state the world is in, not merely that a call succeeded. Returning the resulting record, with its identifier and status, lets the agent verify rather than guess. Returning nothing but a status code invites a second attempt.

Say explicitly when a call was deduplicated. A response that reports the refund already exists and was created at a given time gives the agent something to reason about, and it prevents the second-order failure where the agent concludes its action had no effect and tries a different approach.

Where a tool cannot be made idempotent, mark it in the schema and require confirmation. Some actions genuinely cannot be repeated safely, and those are the ones that warrant a human in the loop.

Reads, writes and the awkward middle

Reads are trivially idempotent. Pure writes are manageable with keys and constraints. The awkward cases are actions with external side effects you do not control: sending an email, posting to a third-party API, charging a card.

For those, keep a local ledger of intent. Record that you are about to send, with a derived key, before you send; check the ledger before sending again. It does not make the external system idempotent, but it makes your side of the boundary safe, which is the part you can fix.

And batch carefully. An action that is idempotent individually may not be as a batch, because a partial batch failure leaves you unsure which elements applied — the situation covered in partial failure recovery. Per-item keys solve it; batch-level keys do not.

A checklist for every mutating tool

Ask four questions before you expose any tool that changes something. Can this be expressed declaratively so repetition is harmless? If not, does it accept a key derived from the arguments rather than generated per attempt? Does the response tell the agent the resulting state, including whether the call was deduplicated? And if it can genuinely not be made safe, is it gated behind confirmation?

Tools that pass all four turn a whole class of incidents into a log line. Tools that pass none turn a routine timeout into a customer refunded twice.

Common questions

Should the agent or the tool layer generate idempotency keys?

The tool layer, by hashing the normalised arguments. A model asked to generate keys will produce a fresh one on each retry, which defeats the mechanism entirely, and any key it must remember can be compacted out of context.

Is checking before acting enough to prevent duplicates?

No. Between the check and the action another agent can act, and model latency makes that window unusually wide. Use it to avoid pointless calls, but enforce correctness with a unique constraint or conditional write at the point of mutation.

What about actions that cannot be made idempotent?

Keep a local ledger of intent keyed by the derived operation, so your side of the boundary is safe, and mark the tool in its schema so genuinely irreversible actions can be gated behind human confirmation.

Similar articles

Rollback Strategies for Agents That Changed Things
AI Agents
AI Agents·9 min read

Rollback Strategies for Agents That Changed Things

An agent stopped halfway through eleven changes. Checkpoints, compensating actions, staging areas and the undo plan you should require before it acts.

Read
Tool Call Retries: Retry the Transport, Not the Judgement
AI Agents
AI Agents·8 min read

Tool Call Retries: Retry the Transport, Not the Judgement

Agents retry constantly, and most of it is wasted. How to tell a transport failure from a wrong decision, and what each one actually needs.

Read
Agent Failure Modes: A Taxonomy Worth Memorising
AI Agents
AI Agents·9 min read

Agent Failure Modes: A Taxonomy Worth Memorising

Agents fail in about eight recognisable ways, and each one needs a different fix. A field guide to spotting them from a trace and knowing what to change.

Read