Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Conditional Writes and Lost-Update Prevention

Last updated: 7 Oct 20266 min read
tutorial
IntermediateBy AITrove Editorial

A lost update occurs when two clients read the same resource and a later save silently overwrites the first client's change. A conditional write makes the client's observed version part of the request. The server emits a strong representation validator, and the client sends that validator in If-Match when changing the case. If the validator no longer matches, the server rejects the write before applying it. A missing required precondition can receive a distinct response from a failed precondition. This only works when every relevant representation change advances the validator and the comparison happens atomically with the write, not in a separate read followed by an unchecked update.

Working case

Reviewers 29 and 31 both open case 47 at version 62. Reviewer 29 adds a safety note and saves version 63. Reviewer 31 still has version 62 and changes the status to resolved. Without a precondition, the second save can replace the note or overwrite a decision made from stale context. The server rejects reviewer 31's old validator. The interface fetches the current case, shows the difference, and asks for an informed merge or new action. It must preserve reviewer 31's unsaved text while doing so.

Implementation boundary

javascript
function conditionalCaseUpdate(ifMatch, currentVersion) {
  if (ifMatch === null) return { status: 428, nextVersion: currentVersion };
  const expectedTag = `"case-47-v${currentVersion}"`;
  if (ifMatch !== expectedTag) return { status: 412, nextVersion: currentVersion };
  return { status: 200, nextVersion: currentVersion + 1 };
}
console.log(conditionalCaseUpdate(`"case-47-v62"`, 63).status);
// Output: 412

The function illustrates response decisions, not a transaction. In production, compare the current version and apply the mutation in one atomic database operation, then return the new strong validator with the representation. If a case has multiple variants, be precise about which selected representation the validator covers. A weak validator is not suitable for a lost-update guard. Authorization and field validation still run; a matching validator does not grant permission or make the submitted data valid. For a failed condition, return enough safe current-state information for recovery without leaking another user's private fields.

Cost and boundaries

A version check is O(1) for one record, and an atomic conditional update can use the record key and version in a single indexed write. The greater cost is the conflict workflow: users may need to review differences and reapply a change. A validator stored per resource adds little data, but every relevant mutation must advance it consistently. High-write records can see frequent conflicts. Do not hide that by retrying a conflicting write automatically; an automatic retry can reintroduce the overwrite the precondition was meant to prevent.

Failure trace

A handler reads version 62, checks If-Match, and then writes without including the version in the database update predicate. Another request commits version 63 between the check and write, so both saves succeed. The API reports a new validator even though one edit was lost. Reproduce with two concurrent requests and move the comparison into the atomic write. Separately test an omitted header and a stale one, since they are different client errors. Preserve the rejected user's draft during recovery.

Verification

  • Two concurrent edits from one version cannot both overwrite the same record silently.
  • Missing and stale preconditions produce distinct recoverable responses.
  • Conflict recovery preserves the user's draft and rechecks authorization.

Practice drill

Open case 47 in two sessions at version 62. Save a note in one and a status change in the other. The second request must not silently win. Inspect the HTTP status, returned validator, and stored record after both orders. Remove If-Match and check the required-precondition response. Then deliberately race the server between validation and persistence; if both writes succeed, the database condition is missing. Repeat with a user who lacks permission to ensure the validator is not treated as authority.

Decision note

Use a strong conditional validator for collaborative writes and enforce it in the same atomic operation that changes the resource.

Common Mistakes

  • Checking a version in one query and writing without the version predicate.
  • Using a weak validator as a lost-update guard.
  • Automatically retrying a rejected conflict with the newest version.

Connected lessons

API Mutation and Failure Contracts; Request Deadlines, Retries, and Backoff; Accepted Operations and Status Resources; Structured API Errors and Recovery; HTTP caching: validate a changed representation with an ETag; Transactions and Concurrent Writes; Idempotent Write Requests and Lost Responses.

Apply and check

Build Project: conflict-safe case API and review Web Development: API mutation contracts quiz.

Further connections

Optimistic Mutations and Rollback; Autosave, Draft Recovery, and Conflicts.

Further connections

Reorder Controls Without Dragging.

Further connections

Cross-Tab Invalidation and Version Checks; Collaborative Conflicts and Presence Expiry.

Further connections

Replica Lag, Read-Your-Write, and Version Cursors.

Further connections

Early Data Replay and Safe Request Admission.

web-tech
web-development
Storage details