{"record":{"id":"2b869d9990ff6dd1","repo":"stalwartlabs/stalwart","slug":"precondition-failed","errorCode":null,"errorMessage":"Precondition Failed","messagePattern":"Precondition Failed","errorType":"http","errorClass":"ScimError","httpStatus":412,"severity":"error","filePath":"crates/scim-proto/src/message/error.rs","lineNumber":179,"sourceCode":"\n    pub fn unauthorized() -> Self {\n        Error::new(401)\n    }\n\n    pub fn forbidden(detail: impl Into<Cow<'static, str>>) -> Self {\n        Error::new(403).with_detail(detail)\n    }\n\n    pub fn not_found() -> Self {\n        Error::new(404)\n    }\n\n    pub fn conflict(detail: impl Into<Cow<'static, str>>) -> Self {\n        Error::new(409).with_detail(detail)\n    }\n\n    pub fn precondition_failed() -> Self {\n        Error::new(412)\n    }\n\n    pub fn max_operations_exceeded(max_operations: usize) -> Self {\n        Error::new(413).with_detail(format!(\n            \"The number of operations in the bulk request exceeds the maxOperations ({max_operations}).\"\n        ))\n    }\n\n    pub fn max_payload_size_exceeded(max_payload_size: usize) -> Self {\n        Error::new(413).with_detail(format!(\n            \"The size of the bulk operation exceeds the maxPayloadSize ({max_payload_size}).\"\n        ))\n    }\n\n    pub fn internal_error() -> Self {\n        Error::new(500)\n    }\n","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/stalwartlabs/stalwart/blob/e96200385781a6a9995a8b839ac27d6c75a983ee/crates/scim-proto/src/message/error.rs#L161-L197","documentation":"A SCIM Error with HTTP status 412 (\"Precondition Failed\"), built by `Error::precondition_failed()`. It indicates that a conditional request precondition supplied by the client (e.g. an If-Match ETag used for optimistic concurrency) did not match the current state of the resource.","triggerScenarios":"PUT/PATCH/DELETE requests carrying an If-Match header whose ETag no longer matches the resource's current version, so the server responds with `Error::precondition_failed()`.","commonSituations":"Two admins edit the same user concurrently and one saves after the other; a client caches a resource, the resource changes, then the client performs a conditional update with the stale ETag.","solutions":["Re-fetch the resource to obtain the current ETag/version, reapply your change, and retry the conditional request.","If the resource changed in ways that invalidate your change, merge manually before retrying.","Only send If-Match when you actually intend compare-and-swap semantics; otherwise omit the precondition."],"exampleFix":"// before\nclient.put_with_if_match(user.id, stale_etag, user).await?;\n// after\nlet fresh = client.get_user(&user.id).await?; // obtains current etag\nclient.put_with_if_match(&fresh.id, &fresh.etag, merged_user).await?;","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.put_with_if_match(id, &etag, body).await {\n    Err(e) if e.status() == 412 => {\n        let fresh = client.get_user(&id).await?;\n        client.put_with_if_match(&fresh.id, &fresh.etag, merged(&fresh, body)).await?;\n    }\n    other => other?,\n}","preventionTips":["Always re-fetch the resource immediately before a conditional write to get a fresh ETag.","Keep conditional-update retry logic with bounded attempts to avoid infinite loops.","Detect concurrent editors and surface merge conflicts to users instead of blind overwrites."],"tags":["scim","http-412","etag"],"backgroundTag":"invalid-state-transition","analyzedSha":"e96200385781a6a9995a8b839ac27d6c75a983ee","analyzedAt":"2026-09-06T22:07:17.982Z","contentChangedAt":"2026-09-06T22:07:17.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}