It is already the latest posts!
It is already the oldest posts!

agent runtime lab en · 2026 · Technical Research Note

10. Preventing Duplicate Side Effects

Retrying a model call spends computation; retrying a send, payment, or create operation can change the external world twice

Using idempotency keys, request fingerprints, external status queries, and recovery states for the crash window after an action.

Research edition · 8 chapters · 4 minute read · Updated 2026-07-27

Edition A · 中文 B · English
SCROLL

An Agent asks a tool to send email. The service accepts the request, but the local process exits before recording the result. On recovery, the trace contains “started” but not “completed.”

Repeating the call can send two messages.

What idempotency provides

An idempotent operation has the same externally observable result whether applied once or repeatedly. Reading a file is close to naturally idempotent. Sending a message, creating an order, and appending a record generally are not.

A runtime can attach an idempotency key to a side-effecting call. A service receiving the same key returns the first outcome instead of executing again.

FieldPurpose
operation_idRuntime identity for the action
idempotency_keyExternal deduplication identity
request_fingerprintProves arguments did not change
external_idResource identity returned by the service
statusStarted, completed, or unknown

The key is bound to normalized arguments. Reusing it after changing parameters must not return an unrelated old result.

Three tool classes recover differently

Tool classExampleRecovery
Read-onlyRead a fileRetry
Queryable side effectCreate a ticketQuery by key or external identifier
Unqueryable side effectSend without receiptMark unknown and request human decision

One call protocol does not imply one retry policy.

Persist intent before execution

Before the external call, persist the normalized argument summary, permission decision, and idempotency key. After the call, save the external identifier and result. This order narrows the window in which the action happened without any local record.

It cannot remove all uncertainty. A timeout can occur after service completion but before the response arrives. Server-side idempotency or a status endpoint remains necessary.

The model does not decide retry safety

The model may propose a retry from an error message. The runtime decides from deterministic metadata: side-effect class, idempotency support, query support, retry count, and permission validity.

A fingerprint prevents incorrect reuse

The key identifies the logical action. The fingerprint identifies its normalized parameters. A repeated key with the same fingerprint returns the original outcome. A repeated key with a different fingerprint produces a conflict.

Canonicalization fixes field order, path representation, and default values before hashing. Otherwise equivalent requests diverge or different requests collapse.

Deduplication records have a lifetime

Records cannot be stored forever, but they cannot expire while recovery remains possible. Retention covers the maximum client retry window, queue delay, and manual recovery period. Tool contracts define whether a reused key after expiration starts a new action or is rejected.

Fault injection

Terminate the process after external success and before tool.completed. On recovery verify:

  1. The same idempotency key is reused.
  2. External status is queried first.
  3. The same approved action does not request approval again unnecessarily.
  4. Changed arguments create a new operation or a conflict.
  5. An unconfirmed outcome becomes unknown, not an automatic retry.

Also submit the same key concurrently and verify that only one executor performs the action. Check how failed outcomes may be retried and whether the status API returns the original external identifier.

“Retry at most three times” limits duplication; it does not prevent it. Reliable recovery combines action semantics, persistence order, and external API support.

The key identifies one logical intent

An idempotency key and request fingerprint form one operation. Reusing a key with a different recipient or body is rejected.

Records distinguish reserved, executing, succeeded, failed_retryable, and failed_final. A duplicate either reuses a result, waits for the current executor, or follows a proven retry path.

A local transaction cannot atomically include a remote email or payment. The process can stop after remote acceptance and before local commit. Recovery passes the key downstream, queries business state, or performs an explicit compensating action.

Fault injection stops before and after intent persistence, remote acceptance, and result commit. Many attempts may appear in the trace, but the external system contains one logical object and the runtime accepts one result.

Statement: If no specific statement in the content, the copyright belongs to sshipanoo . Reprint please indicate the link of this article.

(The content is authorized with CC BY-NC-SA 4.0 protocol)

Title:10. Preventing Duplicate Side Effects

Link:https://www.sshipanoo.com/en/blog/ai/agent-runtime-lab/preventing-duplicate-agent-side-effects/