The direct answer
Use optimistic concurrency control when an AI agent reads a resource, proposes a change, and writes later. Read the resource’s current strong ETag, preserve that value through planning and human review, and send the write with If-Match. The provider should execute the request only if that validator still matches the selected representation when the precondition is evaluated. If another user or process changed the selected representation first, a compliant provider must not apply the stale write and will normally report 412 Precondition Failed under its documented contract.
For an AI-agent workflow, the safe sequence is:
- Read the target resource and capture its strong
ETag. - Build the proposed update from that exact representation.
- Put the
ETagin the write’sIf-Matchcondition. - Show the condition with the method, path, query, and body during approval.
- Execute only the approved request and condition.
- On
412, read again, reconsider the change, and request new approval. Never silently remove the condition.
This prevents one specific failure: a valid-looking write based on stale state. It does not decide whether the payload is sensible, prevent duplicate submissions, or establish what happened after a network timeout. Those need separate controls.
The lost-update race an approval screen cannot see
Suppose an agent reads account 42 at version 7. The account says:
{
"id": "42",
"reviewStatus": "pending",
"owner": "north-region"
}
The provider returns ETag: "version-7". The agent proposes changing reviewStatus to approved, and an owner reviews that exact payload.
Before the owner releases it, another workflow moves the account to a different owner and the provider advances the record to version 8. An unconditional PATCH that changes only reviewStatus can still succeed, approving a record in a context the reviewer never saw. A full-resource update could also restore the stale owner. Either way, the human approved a request built from version 7, but the provider received it against version 8.
If-Match: "version-7" closes that gap when the provider supports conditional writes. The provider compares the submitted validator with the current representation before applying the method. A mismatch prevents the method from being applied and is normally reported as 412 Precondition Failed.
RFC 9110 defines If-Match specifically as a request precondition and identifies preventing accidental overwrites—the lost-update problem—as its most common use with state-changing methods. The same standard defines 412 Precondition Failed as the response when a request condition evaluates to false against current resource state.
The important boundary is temporal: approval can bind the method, target, payload, and validator a person reviewed, while If-Match asks the provider whether the selected representation still matches that validator at execution time.
ETags are opaque version validators
An ETag is an HTTP validator selected by the origin server. It may resemble a version number or hash, but clients should treat it as an opaque string. RFC 9110’s entity-tag specification leaves generation to the service and distinguishes strong validators from weak ones.
A strong tag looks like this:
ETag: "version-7"
A weak tag is prefixed with W/:
ETag: W/"version-7"
If-Match uses strong comparison. A weak validator can be useful for cache validation while still being unsuitable as proof that the representation has not changed in the way a write precondition requires. Do not remove W/, compute your own tag, normalize the opaque value, or strip its quotes. Use only the form and operation documented by the provider.
Some APIs use a different concurrency token instead of a standard ETag. Google Cloud Storage, for example, documents generation and metageneration preconditions for mutating requests and generally recommends them instead of ETag preconditions; its standard If-Match ETag precondition is listed for data-retrieval requests. The design principle is the same—execute only against an expected version—but the wire contract is provider-specific.
Before designing the agent workflow, verify all three facts in the provider’s current documentation:
- the read operation returns a version validator;
- the intended write accepts that validator as a precondition; and
- a mismatch fails before the mutation is applied.
Do not infer write support merely because a GET response includes an ETag. Some services use tags only for cache-aware reads, and some endpoints support conditional writes while others do not.
Approval, concurrency, idempotency, and reconciliation are different controls
These controls are complementary, not interchangeable:
| Control | Question it answers | Failure it addresses |
|---|---|---|
| Exact human approval | Should this specific request be released? | An unauthorized or unreasonable proposed action |
ETag plus If-Match |
Is the target still the version used to prepare and review the request? | A stale overwrite or lost update |
| Idempotency key | Is this a repeat of the same logical submission? | Duplicate ActionDock submissions; provider duplication only when the provider separately supports and receives an idempotency key |
| Reconciliation | Might the provider have applied the write even though the caller lacks a definitive response? | An ambiguous outcome after dispatch |
An idempotency key does not make stale input current. If the agent submits the same outdated update twice, perfect deduplication still leaves an outdated update. Conversely, a valid If-Match condition does not prove exactly-once execution after a lost response. The provider might have applied the conditional write and advanced the version before the connection failed.
The existing guide to AI-agent API retries and unknown outcomes covers the submission and delivery boundary. Human-in-the-loop approval for AI agents covers who can release an exact request. Concurrency control belongs between those decisions and the provider’s mutation.
A conditional write through ActionDock
ActionDock supports an optional input.ifMatch value on integration.execute for providers that enforce conditional writes. A practical flow is:
- Configure an approved connection that permits the required read and write methods.
- Call
integration.fetchfor the target resource. - Copy
output.headers.etag, including its quotes. - Build the proposed write and include that value as
input.ifMatch. - Let the signed-in workspace owner review the exact request.
- Wait for the job’s terminal state instead of resubmitting it.
An HTTP submission can look like this:
{
"workflowId": "account-42-review",
"workflowName": "Approve the reviewed account version",
"input": {
"connectionId": "<connection UUID>",
"method": "PATCH",
"path": "/accounts/42",
"ifMatch": "\"version-7\"",
"body": {
"reviewStatus": "approved"
}
}
}
The escaped quotes are JSON syntax. The actual HTTP header sent to the provider is:
If-Match: "version-7"
ActionDock accepts one quoted strong ETag of at most 1,024 characters on integration.execute writes. It rejects weak tags, wildcards, tag lists, and unquoted values; integration.fetch has no ifMatch input. The value is included in the owner approval preview. Adding, changing, or removing it after approval invalidates the approved snapshot instead of changing the request behind the owner’s decision.
At execution, ActionDock sends that value as the provider’s If-Match header and adds any configured server-held credential. If the provider returns 412, the job becomes failed, the request and bounded provider response remain part of the execution record, and ActionDock does not retry the write automatically.
This behavior is documented in the current agent integration guide. It remains subject to the product boundary: ActionDock can carry and bind the condition, but only the destination API can evaluate its resource version. A provider that ignores If-Match removes the concurrency guarantee.
What to do after 412 Precondition Failed
A 412 is a safety result, not a transient transport error. It means the precondition was false when the server evaluated the request. Retrying the same stale write unchanged will normally fail again while the current validator remains different; deleting the header converts a safe conflict into an unconditional mutation.
Use this recovery loop:
- Keep the failed job. Preserve its request, ETag, approval event, provider response, and timestamps.
- Read the resource again. Obtain the current representation and its new validator.
- Compare meaning, not only fields. Determine who changed the resource and whether the original goal still applies.
- Recompute the proposal. Merge only when the business rule makes that safe. Otherwise stop or ask for a new decision.
- Use a new logical submission. Create a new idempotency key, include the new strong ETag, and obtain new approval.
- Never downgrade silently. Do not remove the condition just to make the next request pass.
This is intentionally more conservative than an automatic retry. The state that justified the original request has changed, so the decision itself may need to change.
Some APIs require conditional requests and can answer 428 Precondition Required when a client omits one. RFC 6585 describes 428 as a way for an origin server to avoid lost updates. Treat that response as an instruction to use the provider’s documented precondition flow, not as permission to invent a validator.
What a timeout means even with If-Match
If-Match narrows which version can be changed. It does not remove distributed-systems uncertainty.
Consider this sequence:
- The provider receives
PATCH /accounts/42withIf-Match: "version-7". - Version 7 matches, so the provider applies the update and advances to version 8.
- The response is lost before ActionDock receives it.
The condition may have succeeded, yet the caller has no definitive response. ActionDock marks an ambiguous dispatched write as execution_unknown and suppresses blind retry. The operator must inspect the provider’s authoritative state before deciding whether another write is appropriate.
That is not the same as 412:
| Result | What is known | Next step |
|---|---|---|
| Provider success response | The provider reported that it accepted the conditional operation | Keep the receipt and verify any business outcome that matters |
412 Precondition Failed |
The condition was false, so the provider reports that it did not apply this request | Read current state and prepare a new proposal if still needed |
428 Precondition Required |
The provider requires a condition that the request omitted | Follow the provider’s documented conditional-write contract |
execution_unknown after dispatch |
The provider might have applied the write, but ActionDock lacks a definitive response | Reconcile provider state; do not submit a fresh key blindly |
For evidence design, see what to log for AI-agent API actions. A durable record should make the reviewed version and the actual outcome distinguishable without claiming independent proof of downstream state.
Provider support varies by operation
Conditional writes are not merely theoretical. Amazon S3 documents If-Match conditional writes for selected object operations and returns 412 when the supplied ETag does not match. Microsoft’s API design guidance likewise describes ETags for optimistic concurrency with If-Match on updates and 412 for a changed resource.
Those examples do not create a universal contract. Support can differ by API version, resource type, method, SDK, proxy, or deployment. An ETag may describe the response representation rather than every business fact you care about. A bulk endpoint may apply a condition to the collection, not each member. A PATCH implementation may have different conflict semantics from PUT or DELETE.
Test the exact operation you plan to expose to an agent:
- Capture the validator from a real read in a non-production environment.
- Confirm an unchanged resource accepts the conditional write.
- Change the resource independently and confirm the stale request returns
412without altering it. - Confirm the current validator changes after a successful write that changes the selected representation.
- Test proxy and SDK behavior so the quotes and header survive intact.
- Simulate a lost response and verify the workflow stops for reconciliation.
ActionDock’s approved API connection workflow can supervise the request only when it is routed through ActionDock. A direct browser session, provider credential, or alternate connector bypasses that boundary.
A decision policy for concurrency-safe agent writes
- Before approval: Require the provider’s documented version condition whenever one exists; preserve the validator exactly and bind it to the connection, destination, method, path, query, and body.
- On
412: Stop, re-read, recompute, and request new approval with a new idempotency key. - On an ambiguous dispatched result: Reconcile provider state before any new submission.
- Without an enforceable precondition: Document the gap and reduce the action’s scope or choose a safer operation.
Optimistic concurrency is valuable precisely because it turns a silent overwrite into an explicit branch. For AI agents, that branch should lead back to fresh evidence and a fresh decision—not to an unconditional retry.
Frequently asked questions
Is If-Match a lock?
No. It does not reserve the resource while an agent reasons or a human reviews. Other actors can still update it. If-Match makes the later write conditional on the reviewed version still being current.
Is a 412 response safe to retry automatically?
Not with the same stale state. Read the resource again, reconsider the proposal, use the new validator, and obtain new approval. Removing If-Match is not a retry; it is a weaker request.
Does an ETag guarantee the whole business object is unchanged?
Only according to the origin server’s validator semantics. Verify what the provider says the tag represents. Treat it as opaque and do not infer stronger coverage than the provider documents.
Does If-Match replace an idempotency key?
No. If-Match protects the expected resource version. An idempotency key identifies a logical submission. A robust workflow can need both, plus approval and reconciliation.
Can ActionDock add optimistic concurrency to an API that does not support it?
No. ActionDock can bind a strong ETag into the approved request and send it as If-Match. The provider must enforce the condition for it to prevent a lost update.
