Skip to content
Skip to content

Idempotency keys and safe retries

What to do when a submit response is lost: find the existing job, retry safely, and avoid creating a second one.

Updated

A lost response is an unknown outcome

Suppose your agent's submit call times out after the server receives the request. The timeout does not prove that admission failed. Keep the original request body and key, read the existing job, and continue from the identity you saved. Do not create a second job just to discover what happened.

  1. Keep the original request body, key, account, quote and quote-bound job ID together in your own request record.
  2. Read GET /v1/jobs/{id} using that job ID. In the TypeScript client, the method is getJob(jobId).
  3. If the job is present, follow its current state. Do not submit again merely to check progress.
  4. If you cannot establish the outcome, preserve the uncertainty. A bounded retry uses the original body and key while the quote remains valid.

A failed read is not proof that the job does not exist. If read-back remains unavailable or the quote has expired, pause and reconcile through support. Share safe job and request references, not credentials or input content.

The Compute paper's recovery section explains why recovery keeps the original job identity and limits the state that changes.

Keep one identity for one request

Save your request body and idempotency key before your agent submits work. Save the prepared task brief with that request: frozen instructions and rubric, input snapshot, operation and output schema, stable IDs, required evidence and acceptance rule. An exact recovery keeps those identities unchanged. Changing any of them is revised work, even when the same source file or item IDs are reused.

Every Compute REST POST requires an Idempotency-Key header. Use 8–128 ASCII characters: a letter or digit first, then letters, digits, ., _, :, or -. For a job, the header must match the body's idempotency_key and the signed quote's key.

Keep retry kinds separate

Distinguish these four repeat or change cases:

RepeatIdentity and budgetWhat it means
Transport or upload retrySame body, artifact, attempt identity and idempotency key; outside compute retry budgetLithi reconciles or resends the same request after a network fault, interrupted upload or lost acknowledgement. It is not a new attempt or a second charge.
Bounded compute retrySame logical job, with a sequential new attempt and fence bounded by retry policy, exposure, capacity, budget and deadlineA lease, executor or transient native failure may receive a replacement attempt without another customer approval. The original scope and maximum stay fixed, owner exposure still counts, and concurrent hedges are rejected.
Accepted-result recoverySame accepted result, artifact and request identity; outside compute retry budgetA finalizer, outbox or delivery repair replays the accepted result or durable state. It does not recompute the work.
Deliberately revised workNew body, quote, approval and idempotency keyYou changed the input, policy, destination, deadline or desired operation. This is new customer-authorized work.

You approve the admitted job or a covering bounded policy once. human_approve_each_run means one customer run, not every physical attempt. No human approves a retry, redrive or repair while it remains within that admitted scope. The retry policy controls compute attempts; it does not make an uncertain transport response safe to replace with another job. Reconcile the original identity first.

Choose the action that matches the situation

SituationAction
Same intent, retryable error, unchanged valid requestRepeat the identical body with the same key.
Admission is already knownRead the existing job and its results.
Submission outcome is unknownReconcile the original job; never rotate its key to escape uncertainty.
Body changedResolve the original intent first. Quote and approve the revised work separately.
Quote expiredCheck whether the original job was admitted. Obtain a fresh quote for work that still needs submission.
Deliberately new workRecord the new intent, obtain its quote and approval, and use a new key.
Only delivery failedRecover delivery of the existing result, not a new compute run.

Preserve the body as well as the key

Replaying a job means keeping its artifact, operation, verification, deadline, destination, and correlation fields unchanged. Keep the brief's instructions, rubric and output schema fixed as well. Rebuilding the body with a new timestamp is not an exact replay.

The TypeScript client's bounded retries preserve the serialized body and key within one call. Across a process restart, your application must restore its saved request. Do not assume a newly generated key identifies the previous call.

A changed-body refusal is not permission to keep trying different keys. Correct the original body for an exact replay, or deliberately authorize new work after reconciliation.

Keep quote expiry separate from retry identity

An expired quote cannot authorize a new admission. A fresh quote may change fields bound to the request, even when your business goal is unchanged. Review those changes and obtain the required approval before submitting again. See Compute availability and access approval when the operation or account fit has changed.

Do not assume an idempotency record lives forever. Keep your own request-to-job mapping and reconcile old attempts before creating replacements. A fresh quote after expiry may change the forecast, capacity or deadline terms, so it is a new approved intent even when the business goal is similar.

Confirm recovery without duplicating work

Successful recovery identifies the same quote-bound job, not a second job that happens to use the same input. Compare the returned job ID and follow its state and result references.

Physical execution attempts are not automatically accepted customer billing units. Retries are not new billing units: the quote and its usage policy define which accepted unit contributes to customer usage; use the usage and receipt records for that decision. A replacement attempt can remain unbilled as a duplicate while its owner exposure still counts against the approved policy.

If the result is retained and authorised, zero account credit does not by itself block its recovery or delivery-link renewal; retention and access permission still control what you may read.

When only a destination write failed, use delivery recovery without rerunning compute. Retrieve or redeliver the same accepted result, keep its identity intact, and do not submit the input again. For file and digest checks, continue with Read and verify Compute result files.

Was this page helpful?