AI Agent Retries Must Not Repeat the Real-World Action shown as one approved action receipt blocking a duplicate retry.
Last edited on August 4, 2026

An AI agent asks a tool to create a DNS record. The provider accepts the change, but the HTTP response disappears before the worker receives it. Ten seconds later, the orchestration layer sees a timeout. That timeout proves only that the caller lacks a result. It does not prove the action failed.

Repeating the call may create a second ticket, send another message, trigger another deployment, or mutate a record that already changed. Voxfor’s guide to hop-relative nginx timeout evidence explains the same boundary at a proxy: the status recorded by one hop describes what that hop observed, not necessarily what every downstream system did.

Safe agent retries therefore need more than a prompt such as “try again if the tool fails.” The application must give each intended business action a stable identity, persist its state outside model context, bind approval to exact arguments, and reconcile an unknown result before another mutation. The goal is not a vague exactly-once promise. The goal is to prevent, detect, or reconcile repeated effects.

A timeout creates an unknown result, not permission to retry

Model calls, tool calls, and business effects are different events. A model may select create_ticket; an executor may dispatch the request; the target may commit the ticket; and the response may fail on the return path. Collapsing those events into one success boolean hides the dangerous middle.

HTTP itself does not make every operation safe to repeat. RFC 9110 defines idempotency by the intended server effect and warns against automatically retrying non-idempotent requests unless the client knows their semantics are idempotent or can detect that the original request was not applied. An API’s POST endpoint can still provide idempotency through a documented key, but the client must use that contract correctly.

Separate two retry layers before changing policy:

  • Trigger deduplication prevents the same upstream event from launching two agent runs.
  • Action deduplication prevents two runs, workers, or resumed checkpoints from applying the same business effect twice.

OpenAI’s current Workspace Agent trigger documentation makes that distinction concrete. conversation_key continues a conversation, while Idempotency-Key safely retries the same trigger event. Neither value automatically deduplicates a separate external API call later in the agent run.

Name the action before the model can call it

Start with an application-owned action_id, not a model-generated explanation. Derive it from the upstream event and intended effect, or create it once when the application accepts the request. Reusing a key is correct only for another attempt at the same logical action with the same protected arguments.

A minimal durable receipt can look like this:

{
  "action_id": "act_01K2DNS7T6M3",
  "business_key": "dns:example.com:A:203.0.113.42",
  "effect": "upsert_dns_record",
  "arguments_sha256": "sha256:REPLACE_WITH_REAL_DIGEST",
  "approval_id": "apr_01K2DNS8B1Q9",
  "policy_version": "dns-change-v3",
  "attempt": 1,
  "state": "prepared"
}

business_key should identify what the target considers the same object or operation. For email it might be a campaign recipient plus template version; for a deployment it might be service plus release digest; for DNS it may be zone, owner name, record type, and desired value. A random retry UUID defeats deduplication because every attempt appears new.

The argument digest protects approval integrity. If a resumed agent changes the hostname, recipient, amount, environment, or command, the prior approval no longer covers the action. Request new approval instead of carrying permission forward because the tool name stayed the same.

Keep credentials and authorization outside the receipt. Voxfor’s AI agent workspace permissions remain the separate least-privilege boundary: a stable action ID prevents duplicate intent; it does not justify broader file, shell, network, or account access.

Keep one receipt across trigger, approval, and execution

Store the receipt in a durable database or workflow store shared by every worker able to execute the action. Chat history, a process-local dictionary, or a queue-delivery counter is not enough when another replica can take over after a crash.

Write state before crossing each irreversible boundary. Persist approved after approval verification. Persist sent in the same controlled handoff that authorizes dispatch, then store the target’s resource ID, request ID, or authoritative result as confirmed. Where the target supports an idempotency key, send the stable action_id or a documented derivative on every retry of that same action.

AI agent action receipt state pathA left-to-right path from prepared to approved to sent. Sent can become confirmed, or branch to outcome unknown. Outcome unknown must pass through reconciliation before either confirmation or a new attempt.PreparedApprovedSentConfirmedOutcome unknownReconcile before retryresponse lost
A missing response creates an outcome-unknown branch. Reconciliation, not an automatic second mutation, is the route back to a known state.

LangGraph persistence stores graph state as checkpoints, while its interrupt guidance notes that a resumed node restarts from the beginning and side effects before an interrupt should be idempotent. That is why approval UI and execution state must refer to one receipt instead of relying on where the model appears to pause.

Transport sessions solve another problem. Voxfor’s analysis of explicit MCP state handles shows how useful state can survive replica changes. An action receipt applies the same ownership principle to a mutation, but its identity must remain stable even when the model conversation or transport session changes.

Four outcomes require four different next moves

Do not feed every exception into one exponential-backoff loop. Classify the receipt from evidence that exists outside the model’s prose.

Observed outcome What it proves Safe next move
Never dispatched No request crossed the executor boundary Retry with the same action ID after the cause is corrected
Rejected before effect Target returned an authoritative non-application result Fix input or authorization; retry only under the same logical intent
Confirmed effect Target resource ID, version, or idempotent replay receipt exists Return the stored result; do not mutate again
Outcome unknown Dispatch occurred but authoritative result is absent Query by business key or idempotency key; reconcile before any retry

Queue acknowledgment cannot replace this table. Voxfor’s JetStream redelivery guide separates pending work from delivered-but-unacknowledged work, yet even a correct redelivery policy still needs an idempotent business handler. A worker may complete the external effect and crash before acknowledging the message.

Temporal makes the same risk explicit: Activities may retry and should be idempotent, while its Python error-handling guidance warns that losing a permanent failure’s non-retryable classification can make the framework try again. Backoff reduces pressure; it does not change whether repetition is safe.

Put retry policy outside the prompt

Prompts can help a model explain an error, but application code must own retry eligibility. The executor should accept only declared transitions, reject changed argument hashes, and return a stored result when the same confirmed action arrives again.

retry_policy:
  never_dispatched: automatic_same_action_id
  rejected_transient: bounded_same_action_id
  rejected_permanent: stop_for_new_input_or_approval
  confirmed: return_stored_receipt
  outcome_unknown: reconcile_then_decide

Bound attempts by error class and time budget. Rate limits, connection refusal before dispatch, and target maintenance may be transient. Invalid arguments, revoked authorization, policy denial, and unsupported operations do not become safer because time passed. Preserve the original error class instead of wrapping every failure in ToolError.

OpenAI’s Programmatic Tool Calling guidance recommends direct calls for writes or approval-sensitive actions and explicitly separates bounded orchestration from side-effecting work that must not be repeated. The practical lesson is broader than one SDK: keep write authorization, attempt count, and terminal-state rules in deterministic application logic.

Reconcile before repeating an uncertain mutation

Reconciliation asks the target what exists now. Use an idempotency-key lookup when the API exposes one; otherwise query by stable business key and compare the observed resource with the approved arguments. A DNS worker can read the exact record set, a ticket worker can search an external reference field, and a deployment worker can compare release digest plus environment.

Follow a fail-closed order:

  1. Lock or claim the action receipt so another worker cannot reconcile and retry simultaneously.
  2. Read the target through an authoritative interface, not a cached dashboard.
  3. If the approved effect exists exactly once, store its target ID and mark confirmed.
  4. If it does not exist and evidence proves non-application, permit one bounded attempt with the same action ID.
  5. If several possible matches exist or evidence is incomplete, mark manual_reconciliation; do not ask the model to guess.

Evidence can also disappear. When an audit pipeline loses records, Voxfor’s Linux Audit evidence boundary requires operators to state honestly what can no longer be proven. Apply the same rule here: missing receipts do not become proof of failure. Escalate uncertainty rather than reconstructing a convenient success story from chat text.

Retention must exceed every realistic replay path: producer retries, queue redelivery, workflow resume, operator requeue, and the target’s idempotency window. Archive or compact receipts only after their business effects have an independent durable identifier and the retry path can no longer reach them.

External operation does not change ownership

Self-managed teams may host the executor, database, and workflow engine themselves; another team may operate some or all of that stack. The business-effect contract remains with the workflow owner.

The contract stays the same when a team uses autonomous AI workers on VPS or dedicated servers: the workflow owner still defines the business key, approval scope, replay rule, and reconciliation owner. Delegating operation changes who implements the controls, not who defines the meaning of a duplicate business effect.

Handoffs should name who can approve, who may release an unknown receipt, which target query is authoritative, how long receipts remain available, and what evidence closes the action. A managed operator can implement and monitor the mechanism, but cannot invent the client’s definition of “same order,” “same customer message,” or “same production change.”

FAQ: Agent retry boundaries

Can an AI agent safely retry every failed tool call?

Only under a proven retry contract. A failed or missing response does not prove the external effect failed. Retry automatically when durable state proves non-dispatch or the target guarantees that the same stable idempotency key returns the original outcome.

Is a conversation ID an idempotency key?

Conversation continuity and action identity solve different problems. A conversation ID groups model context; an idempotency key identifies one logical action. One conversation can contain many actions, and the same action may resume in another conversation or worker.

Where should AI action idempotency state be stored?

Store action receipts in a durable database or workflow store shared by every executor replica. Process memory and chat transcripts do not provide reliable cross-worker exclusion or retention.

What if the external API has no idempotency-key support?

Use a stable business key and reconcile through an authoritative read before writing again. If the target cannot identify the prior effect reliably, require manual resolution rather than automatic retry.

Should approval survive changed tool arguments?

Approval must bind to normalized arguments, their digest, the effect, and policy version. Any material argument change creates a new approval decision even when the tool name is unchanged.

How long should action receipts be retained?

Keep receipts longer than every producer-retry, queue-redelivery, workflow-resume, operator-requeue, and target-deduplication window. Shorter retention can let an old event return after its duplicate evidence disappeared.

Finish with one deliberately lost response

Test the contract on a harmless isolated target. Execute one effect with a stable business key, deliberately drop the success response after the target commits, and let the normal retry path wake up. The second worker should find outcome_unknown, reconcile the existing target object, and return the first result without creating another effect.

Record the trigger key, action ID, approved argument hash, state timestamps, target resource ID, reconciliation query, and final count of external effects. Then repeat the drill with a changed argument and prove prior approval is rejected.

An AI retry is safe when the application can explain why another attempt cannot create another business effect. A confident model response is not that explanation; a durable receipt and authoritative reconciliation are.

Leave a Reply

Your email address will not be published. Required fields are marked *