412 - Precondition Failed
HTTP 412 Precondition Failed means a conditional request precondition evaluated to false on current resource state.
Last reviewed: April 24, 2026|Source-backed guidance under our editorial policy
Start Here
Use the closest compare guide, playbook, or adjacent error page to narrow the decision faster before you start changing production systems.
This page is part of the Error Reference library. Learn more about the project or report a correction.
What Does Precondition Failed Mean?
The request reached the resource, but one of its conditional headers evaluated to false. This is the server protecting consistency: a validator such as If-Match, If-Unmodified-Since, or copy precondition no longer matches current resource state.
Common Causes
- -
If-Matchcarries an outdated ETag after another writer modified the resource. - -
If-Unmodified-Sinceis older than the latest resource timestamp, so the server denies the write to prevent overwrite. - -Object copy or storage preconditions reference stale checksum, generation, or version metadata.
- -A client reuses cached validators from a stale CDN, edge cache, or offline UI snapshot.
- -Mutation logic sends the wrong conditional header for the operation intent.
How to Fix Precondition Failed
- 1Fetch the latest representation and refresh validators before retrying the conditional request.
- 2Send the conditional header that matches operation intent:
If-Matchfor guarded updates,If-None-Matchfor create-if-absent or cache paths. - 3Return or surface current validator metadata so clients can rebase changes rather than replaying stale writes.
- 4Preserve the precondition guard; do not remove it just to force the write through.
Step-by-Step Diagnosis for Precondition Failed
- 1Capture the exact conditional headers and validator values sent on the failing request.
- 2Compare client validators to current origin validators returned by a fresh
GETorHEAD. - 3Trace concurrent writes or cache staleness that can invalidate preconditions between read and write.
- 4Determine whether this is a failed conditional request (
412) or a broader state conflict better represented by409. - 5Retest with updated validators and verify client conflict-resolution logic handles 412 deterministically.
Seen in Production
- -A user edits a document from an old tab, sends stale
If-Match, and the server returns 412 after a newer save already changed the ETag. - -A sync client resumes after offline time and tries to overwrite a resource guarded by
If-Unmodified-Since. - -An object copy request uses stale source-generation metadata and storage rejects the copy precondition.
- -An edge cache serves an older validator to a client, so the next conditional write fails even though the API is healthy.
Conditional Header and Validator Audit
- -Inspect validator mismatch paths (example:
If-Match: "abc"while current ETag is"def"). - -Verify correct conditional mode per use case (example: optimistic update needs
If-Match, cache revalidation needsIf-None-Match).
Concurrency and Cache Staleness Trace
- -Correlate write events between read and mutate windows (example: another client updates resource 200 ms before your PUT).
- -Audit intermediary cache freshness and revalidation behavior (example: stale edge cache serves old validator to writer client).
Decision Shortcut: 412 vs 409
- -If a conditional header evaluated false, stay on 412 and refresh validators.
- -If the request conflicts with business state without a conditional header failure, move to 409.
- -If the client omitted required preconditions entirely, inspect 428 before treating it as a failed precondition.
Wrong Fix to Avoid
- -Do not remove
If-Matchor equivalent validators to make writes succeed under contention. - -Do not blind-retry the same stale conditional request.
- -Do not treat every 412 as a generic conflict; the failed header tells you exactly which guard rejected the request.
Implementation Examples
2026-04-24T14:22:08Z requestId=req_412_71 resource=docs/784
ifMatch="etag-v12" currentEtag="etag-v13" status=412
message="precondition failed: resource changed before update"const latest = await fetch('/api/docs/784');
const etag = latest.headers.get('ETag');
const response = await fetch('/api/docs/784', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'If-Match': etag,
},
body: JSON.stringify({ title: 'Updated title' }),
});
if (response.status === 412) {
// Re-read and rebase instead of replaying the same stale validator.
}rg 'status=412|If-Match|If-Unmodified-Since|precondition failed|etag' application.logIncident Timeline
14:18 UTC
A client reads a representation and stores its validator
Signal: The UI, SDK, or cache keeps an ETag, timestamp, generation, or checksum for a later conditional operation.
Why it matters: The validator is only safe while the resource remains unchanged.
14:21 UTC
Another writer changes the resource first
Signal: Origin state advances and the old validator no longer matches current resource metadata.
Why it matters: The pending conditional request is now stale.
14:22 UTC
The server rejects the stale conditional request with 412
Signal: If-Match, If-Unmodified-Since, or a storage precondition evaluates false.
Why it matters: The guard is working; the client needs fresh state, not an unguarded write.
14:26 UTC
Client refreshes validators and rebases the mutation
Signal: A fresh GET or HEAD supplies current validators and the update is recomputed safely.
Why it matters: That confirms the root cause was stale conditional metadata.
Seen in Production
Optimistic update collides with recent change
Frequency: common
Example: Client sends If-Match from an earlier read, but another writer already updated the record.
Fix: Refresh representation, merge user changes, then retry with latest validator.
Offline client resumes with an old validator
Frequency: common
Example: A mobile client saves after reconnecting, but another device already advanced the resource ETag.
Fix: Force refresh and rebase before conditional write retry.
Object copy precondition references stale generation metadata
Frequency: medium
Example: Storage copy operation fails because source generation or checksum no longer matches.
Fix: Refresh source metadata and rebuild the copy request with current preconditions.
Wrong Fix vs Better Fix
Remove the precondition vs refresh the validator
Wrong fix: Delete If-Match or the storage precondition so the write stops failing.
Better fix: Fetch current validators, merge or rebase the intended change, and retry conditionally.
Why this is better: The precondition is preventing accidental overwrite or stale copy behavior.
Retry same request vs re-read state
Wrong fix: Replay the same stale conditional request immediately.
Better fix: Re-read current state and rebuild the request with fresh validators.
Why this is better: The same stale validator will continue to fail until resource state or request metadata changes.
Blame availability vs inspect validator source
Wrong fix: Treat 412 spikes like a transport or backend health incident.
Better fix: Trace who supplied the old validator: browser tab, CDN cache, offline client, or stale SDK state.
Why this is better: 412 is a deterministic conditional-evaluation result, not a service availability signal.
Debugging Tools
- -Workflow traces with correlation IDs
- -Version/ETag token inspection
- -Queue and orchestration execution logs
- -Concurrency diagnostics
How to Verify the Fix
- -Repeat conditional requests and confirm they succeed only when validators are current.
- -Run parallel update tests to ensure stale validators still fail safely with 412.
- -Confirm client retries now refresh validators instead of replaying stale headers.
- -Verify 409 and 428 paths still behave correctly for non-conditional conflicts and missing preconditions.
How to Prevent Recurrence
- -Adopt optimistic concurrency tokens and idempotency guards for mutating operations.
- -Serialize high-contention writes and enforce deterministic dependency ordering.
- -Monitor precondition and lock-related failure signals with actionable alerts.
- -Return current validators and conflict metadata in 412 responses where API design allows it.
Pro Tip
- -pair 412 responses with a lightweight rebase flow so clients can refresh, merge, and retry without dropping user edits.
Decision Support
Compare Guide
409 Conflict vs 412 Precondition Failed: When to Use Each
Choose 412 when If-Match or If-Unmodified-Since checks fail; choose 409 for state conflicts without failed precondition headers during concurrent updates.
Playbook
Conflict and Concurrency Playbook (409 / 412 / OptimisticLock)
Use this playbook to separate true write conflicts from stale precondition failures, then apply safe re-fetch, optimistic-lock, and retry choices.
Official References
Provider Context
This guidance is specific to HTTP services. Always validate implementation details against official provider documentation before deploying to production.