Skip to content

Field note

AI Tool Timeouts: Did the Action Still Happen?

Check an uncertain action before asking an agent to repeat it.

An agent asks a service to create a booking. The service creates it, but the acknowledgement is lost. The agent sees a timeout and tries again. Without an operation identity that survives the retry, the second request can become a second booking.

This illustrative failure is a distributed systems problem. The language model adds another source of retries, but the protection belongs in the application and the receiving service.

Distinguish a retry from another instruction

Idempotency means repeated requests have the same intended effect as one request. HTTP Semantics, RFC 9110, makes this distinction and cautions against automatically retrying non-idempotent operations without knowing their semantics.

“Book the same appointment because the reply was lost” and “book a second appointment” are different intentions even if their parameters match. Conversely, the same intent might be attempted through a new network connection or after a worker restart.

Have the application create a durable operation ID after the user has settled the action. Do not let the model generate a fresh ID every time it decides to call the tool. Tie the ID to the tenant, actor and action type, and retain a canonical representation of the approved arguments.

Record intent before calling the service

A useful operation record includes the ID, validated arguments, approval reference where required, current state and external result ID. Suggested states are prepared, submitted, confirmed, failed and uncertain.

The uncertain state is essential. It means the application cannot yet tell whether the effect happened. Treating it as failed encourages a duplicate; treating it as confirmed invents success.

Where you control the receiving service, make recording the operation key and applying the business mutation part of the same transaction where possible. The AWS Builders' Library explains why an atomic relationship is needed: a resource created without its duplicate-protection record leaves the next attempt exposed.

An external API sits outside your database transaction. Keep its request and result IDs, use its documented idempotency facility and reconcile the gap between external success and your local record. A local “processed” flag alone cannot close that gap.

Read the provider's idempotency contract

Do not assume every Idempotency-Key header behaves alike. Check the endpoint coverage, key retention period, treatment of failures and response when the same key arrives with different parameters.

For example, Stripe's API v1 documentation describes storing the first executed request's result and returning it for the same key, including some failure results. It also documents parameter checks and a retention boundary. Those details affect recovery; repeatedly sending the same key is not always a way to make a failed operation succeed.

Keep keys free of customer names and other unnecessary personal data. A random opaque identifier is easier to use safely in logs than an email address combined with a booking description.

Give the agent a precise tool result

Return business state rather than a generic error string. A tool response might say that operation OP-1042 has an uncertain outcome and must be checked through a status tool. The status lookup can retrieve the external booking ID or confirm that no operation was accepted.

Do not offer the write tool again merely because the model asks for it. The server should recognise the existing intent and return its known result or uncertainty. If the user changes the date or quantity, require the application to create a new intention with the appropriate review rather than silently changing arguments under an old key.

The Gemini function-calling note introduces write validation. This is the additional lifecycle needed when a valid write crosses a network and the reply is unreliable.

Test the point where acknowledgement is lost

In a sandbox, simulate failure before submission, after external acceptance and before the local success record is saved. Also test two workers attempting the same operation concurrently and a worker restarting with an outstanding request.

For each case, inspect the external records directly. The acceptance condition is one intended business effect and an accurate final operation state, not merely one model tool call. Test what happens after the provider's key retention window expires; old unresolved operations should enter reconciliation rather than automatic replay.

Use bounded retries for transient transport failures and stop when the semantics are uncertain. A person checking one unresolved booking is less work than undoing duplicate bookings and explaining contradictory confirmations.

After deployment, monitor the age of uncertain operations. An idempotency design that prevents duplicates but leaves work pending forever still needs an operational owner and a recovery route.

References

Keep reading

Related notes

26 Aug 2026 · 5 min

MCP Tool Poisoning: Security Checklist

Treat every MCP server's metadata, tool descriptions and returned content as untrusted input until a person or a policy layer has reviewed and approved them.