elsa-workflows/elsa-core · error · BpmnDocumentPreconditionFailedException
The workflow definition has been written since the ETag in…
Error message
The workflow definition has been written since the ETag in If-Match was issued. GET the document again, reapply the edit, and PUT it with the new ETag.
What it means
BpmnInterchangeDocumentService enforces optimistic concurrency: if an If-Match ETag was supplied but the stored definition's ETag (BpmnDocumentETag.From) no longer matches, it throws BpmnDocumentPreconditionFailedException. Someone else (or another process) wrote the definition after your ETag was issued, so your edit is rejected to avoid clobbering their changes.
Solutions
- GET the BPMN document again to obtain the fresh ETag, reapply your edit, and PUT with the new If-Match ETag
- Retry with a short backoff if concurrent writers are expected and your change is idempotent
- Use conditional logic to merge/verify changes before re-submitting
Example fix
// before await client.PutAsync(url, content, new ETag(oldEtag)); // stale // after var doc = await client.GetAsync(url); // returns fresh ETag reapplyEdit(doc); await client.PutAsync(url, serialize(doc), new ETag(doc.Etag));
Defensive patterns
Strategy: retry
Validate before calling
var doc = await getDocument(definitionId); // fresh ETag
if (doc.Etag != expectedEtag) throw new ConcurrencyException("document changed; reapply edit"); Try / catch
try { await put(url, content, ifMatch: etag); }
catch (BpmnDocumentPreconditionFailedException) { var fresh = await get(url); reapply(fresh); await put(url, content, ifMatch: fresh.Etag); } Prevention
- Always GET immediately before PUT and use the returned ETag
- Avoid long edit sessions between GET and PUT
- Design merges rather than blind overwrites for shared documents
When it happens
Trigger: PersistDocumentEditAsync sees expectedETag non-null whose value differs from BpmnDocumentETag.From(current) — i.e. a concurrent write happened between your GET and your PUT.
Common situations: Two Studio sessions or two users editing the same BPMN document, an automation pipeline racing a manual edit, or retrying an old PUT after a previous successful write.
Related errors
- An < : > element declares no ' ', so there is nothing to…
- An < : > element of the ' ' binding declares no ' '.
- The ' ' binding declares the input ' ' more than once. Each…
- The binding to activity type
- The binding names activity type
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/75e9c3f559d9a905.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Bpmn.Interchange/Services/BpmnInterchangeDocumentService.cs:340
string definitionId,
BpmnProcess process,
BpmnProcessDefinition rootDefinition,
BpmnImportAnalysis analysis,
string? expectedETag,
CancellationToken cancellationToken)
{
var filter = WorkflowDefinitionHandle.ByDefinitionId(definitionId, VersionOptions.Latest).ToFilter();
var current = await store.FindAsync(filter, cancellationToken);
if (current is null)
{
throw new BpmnDefinitionNotFoundException(
$"Workflow definition '{definitionId}' does not exist, so its BPMN document cannot be edited.");
}
if (expectedETag is not null && !string.Equals(BpmnDocumentETag.From(current), expectedETag, StringComparison.Ordinal))
{
throw new BpmnDocumentPreconditionFailedException(
"The workflow definition has been written since the ETag in If-Match was issued. GET the document again, reapply the edit, and PUT it with the new ETag.");
}
var expectedId = current.Id;
var expectedVersion = current.Version;
var expectedName = current.Name;
var expectedDescription = current.Description;
var expectedStringData = current.StringData;
var draft = ApplyDocumentEdit(current, process, xml, rootDefinition);
await mediator.SendAsync(new WorkflowDefinitionDraftSaving(draft), cancellationToken);
var result = await store.TryUpdateLatestAsync(
filter,
loaded => loaded.IsLatest
&& loaded.Id == expectedId
&& loaded.Version == expectedVersion
&& loaded.StringData == expectedStringDataView on GitHub (pinned to fe9217bdfa)