Start a conversation Contact
← Research

Every agent retry needs the same operation ID

A timeout does not tell an agent whether its tool call failed. Retrying without the original operation ID can repeat the effect, so idempotency belongs in the tool contract before an agent reaches production.

Consider a hypothetical purchasing agent. It calls create_purchase_order, the procurement system commits the order, and the connection closes before the reply reaches the agent. The trace contains a timeout. The purchase order exists.

The agent has an apparently sensible next move: try again. Its second call might be a transport retry of the same request, another tool call chosen by the model, or a fresh attempt after the whole task resumes. Without a shared identity for the intended operation, the procurement system sees a second instruction and creates a second order.

A retry policy for an agent is incomplete until every effectful tool has an idempotency contract. The contract has to identify the business operation before the first attempt, carry that identity unchanged through every retry, and let the receiving system return the outcome already associated with it. Prompting the model to be careful does not create that property.

A timeout leaves the result unknown

The error observed by the caller and the state of the receiving system are two different facts. A timeout establishes that the caller did not receive a reply. It does not establish that the request failed. The request might be waiting, executing, committed or rejected. Retrying is safe only when the receiving system can distinguish another attempt at the same operation from a new operation with the same parameters.

This is established distributed-systems behaviour rather than a new agent problem. The HTTP Semantics specification defines an idempotent method by its intended effect: sending identical requests more than once has the same intended effect as sending one. It permits automatic repetition after a communication failure for such methods, and cautions against automatically retrying a non-idempotent request unless the client knows the semantics are idempotent or can establish that the first request was not applied. RFC 9110, section 9.2.2

An agent makes the old ambiguity easier to reach. The retry can happen at more than one layer, and those layers do not necessarily share state. An HTTP client might retry a failed connection while the agent runtime also asks the model what to do after the reported failure. A job runner can later resume the task. A maximum step count limits how long this continues. It does not make any repeated effect safe.

One intended operation can be attempted at several layers Fig. 01
  1. 01 Intend The trusted orchestrator assigns an operation ID before the first effectful call.
  2. 02 Attempt Every transport and model-level retry carries that same ID and the same parameters.
  3. 03 Recognise The receiving system atomically associates the ID with the operation and its outcome.
  4. 04 Resolve A repeated request returns the existing outcome or exposes it for reconciliation.

The first stage belongs outside the model. The model may choose the tool and supply its business arguments. The orchestrator should assign the operation ID, attach the task and actor identities, and keep the ID when it resumes. Letting the model invent a fresh key for every call gives each retry a new identity, which defeats the contract while satisfying its schema.

Identical parameters do not mean identical intent

A hash of the arguments looks like an easy duplicate detector. It is not an operation identity. Two legitimate orders for the same item, quantity and supplier can have identical parameters and still be two intended orders. A rephrased retry can also produce slightly different arguments while pursuing one intended order.

AWS describes this distinction in its guidance on making retries safe. It rejects inference from matching parameters as a general solution because identical resource requests can represent separate intentions. Its preferred pattern uses a unique caller-provided request identifier, which makes the caller’s intention explicit and makes the relationship visible in audit logs. The service records the identifier with the result and can return a semantically equivalent response when the request is repeated. AWS Builders’ Library

The receiver has work to do as well. Recording the key and performing the effect must be one atomic decision. If it records the key and then fails before the effect, future attempts can be suppressed forever. If it performs the effect and then fails before recording the key, the next attempt can repeat it. The useful contract is not merely “accepts an idempotency key”. It states when execution is considered to have started, what result is retained, what happens when the same key arrives with different parameters, and how long the record lives.

Stripe’s API documents those choices concretely. It stores the status code and response body after execution begins, returns that stored result for subsequent requests with the same key, and rejects a reused key when the parameters do not match. It also documents that keys may be removed after at least twenty-four hours. That last boundary matters: a task resumed after the receiver has removed the record is a new request as far as that receiver is concerned. Stripe API reference

Put retry semantics in the tool review

An effectful tool should not reach an agent because its request and response schemas look tidy. The design review needs the failure contract as well.

Then test the ambiguity rather than the happy path. In a controlled environment, interrupt the connection after the receiver commits but before the client reads the response. Exercise a transport retry, a model-selected retry and a resumed job. The test passes when each path resolves to the same business object and the audit record shows one intended operation with several attempts. A test that only sends the same request twice misses the exact boundary that causes the incident.

The operation ID also gives human approval a precise object. Approval should bind the actor, business arguments and operation ID before execution. A retry with the same identity is another attempt to carry out the approved operation. A call with a new identity is a new operation and needs to cross the applicable approval boundary again. Without that distinction, the interface can display one confirmation while the system performs the confirmed effect twice.

This extends the earlier argument that irreversibility, rather than autonomy, is the reviewable property of an agent. Reversibility determines which actions deserve the strongest boundary. Idempotency determines whether the recovery mechanism can repeat an action that has already crossed it. An outbox can delay a released effect. It still needs to recognise the same message when a producer retries.

The contract has a boundary

Idempotency does not make a tool correct. It does not prove that the model chose the right supplier, that a person approved the right order, or that a sequence of individually idempotent operations is safe when repeated in a different order. RFC 9110 is careful to define the property around the intended effect of one request. A multi-tool plan needs its own state machine and recovery rules.

Nor does an idempotency key provide permanent deduplication. The receiving system has a retention window, and the task system has queues, pauses and manual recovery paths. Those windows have to be compared. Where the receiver cannot retain a key for the full recovery period, the architecture needs a reconciliation step that looks up the effect by a stable business reference before attempting it again.

Some actions are naturally safe to repeat, and read-only tools do not need this machinery merely because an agent calls them. The requirement belongs where a call creates, changes, sends or releases something. The strength of the contract should follow the consequence and the available reconciliation path.

The architect approving an agent’s tool catalogue is also approving how each tool behaves when the answer disappears. If the catalogue records only inputs, outputs and permissions, it has left out the state the system enters after a timeout. Add operation identity before adding retries. Otherwise reliability at the caller becomes duplication at the system that actually does the work.

Filed under · Architecture · Agents · Tool design · Reliability Inference Institute · 04 Sept 2026

Bring us the question

Reading this because it is on your desk right now?

That is the conversation we are best at. Thirty minutes, a written summary, no obligation.