stalwartlabs/stalwart · error · ScimError
Precondition Failed
Error message
Precondition Failed
What it means
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.
Source
Thrown at crates/scim-proto/src/message/error.rs:179
pub fn unauthorized() -> Self {
Error::new(401)
}
pub fn forbidden(detail: impl Into<Cow<'static, str>>) -> Self {
Error::new(403).with_detail(detail)
}
pub fn not_found() -> Self {
Error::new(404)
}
pub fn conflict(detail: impl Into<Cow<'static, str>>) -> Self {
Error::new(409).with_detail(detail)
}
pub fn precondition_failed() -> Self {
Error::new(412)
}
pub fn max_operations_exceeded(max_operations: usize) -> Self {
Error::new(413).with_detail(format!(
"The number of operations in the bulk request exceeds the maxOperations ({max_operations})."
))
}
pub fn max_payload_size_exceeded(max_payload_size: usize) -> Self {
Error::new(413).with_detail(format!(
"The size of the bulk operation exceeds the maxPayloadSize ({max_payload_size})."
))
}
pub fn internal_error() -> Self {
Error::new(500)
}
View on GitHub (pinned to e962003857)
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.
Example fix
// before client.put_with_if_match(user.id, stale_etag, user).await?; // after let fresh = client.get_user(&user.id).await?; // obtains current etag client.put_with_if_match(&fresh.id, &fresh.etag, merged_user).await?;
Defensive patterns
Strategy: retry
Try / catch
match client.put_with_if_match(id, &etag, body).await {
Err(e) if e.status() == 412 => {
let fresh = client.get_user(&id).await?;
client.put_with_if_match(&fresh.id, &fresh.etag, merged(&fresh, body)).await?;
}
other => other?,
} Prevention
- 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.
When it happens
Trigger: 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()`.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06).
Data as JSON: /api/errors/2b869d9990ff6dd1.
Report an issue: GitHub.