elsa-workflows/elsa-core · error · BpmnInterchangeException

Subprocess element ' ' of process ' ' carries no…

Error message

Subprocess element '{subprocess.ElementId}' of process '{process.ProcessId}' carries no bindingRef, so the body stored for it cannot be written back with it. The document does not carry a subprocess's body, so writing it without one would silently empty the subprocess. Send the element with the bindingRef the document GET returned.

What it means

When re-importing a document, StoredNestedScopesStillDeclaredBy carries across stored subprocess bodies to the new document. If an incoming subprocess element carries no bindingRef, the stored body cannot be reattached — writing it without one would silently empty the subprocess — so BpmnInterchangeException is thrown. The document format deliberately excludes subprocess bodies, so bindingRef is the only way to link the element back to its stored body.

Solutions

  1. Send the subprocess element with the bindingRef exactly as the document GET returned it
  2. Start each edit from the document returned by GET rather than hand-crafted XML
  3. Extend your XML transformations to preserve the bindingRef attribute on subprocess elements

Example fix

// before
<subProcess id="Sub1"/>
// after
<subProcess id="Sub1" bindingRef="stored-body-ref-from-GET"/>
Defensive patterns

Strategy: validation

Validate before calling

foreach (var sp in document.Processes.SelectMany(p => p.Subprocesses))
    if (sp.BindingRef is null) throw new InvalidOperationException($"Subprocess {sp.ElementId} is missing bindingRef");

Try / catch

try { await service.ImportAsync(id, doc); }
catch (BpmnInterchangeException ex) when (ex.Message.Contains("bindingRef")) { restoreBindingRefsFromGetResponse(); }

Prevention

When it happens

Trigger: PUTting/importing a BPMN document in which a subprocess element (subprocess.ElementId within process.ProcessId) that has a stored body omits bindingRef — e.g. the client hand-built the XML instead of echoing the GET response.

Common situations: Manually authoring or transforming the BPMN XML and dropping the bindingRef attribute, running an XML transformation/normalizer that strips unknown attributes, or copying subprocess elements between documents without their bindingRefs.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/fd766316a02966b2. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Bpmn.Interchange/Services/BpmnInterchangeDocumentService.cs:670

            .Where(element => element.LoopCharacteristics is not null)
            .Select(element => element.ElementId)
            .ToHashSet(StringComparer.Ordinal);

        var kept = new List<BpmnWorkBinding>();

        foreach (var process in document.Processes)
        {
            foreach (var subprocess in process.Elements.Where(element => element.ElementType == BpmnElementTypes.SubProcess))
            {
                // Last match wins, as it does inside the writer itself, should a malformed document repeat an id.
                var body = storedBindings.OfType<BpmnWorkBinding.NestedProcess>().LastOrDefault(nested => nested.ElementId == subprocess.ElementId);

                if (body is null)
                    continue;

                if (subprocess.BindingRef is null)
                {
                    throw new BpmnInterchangeException(
                        $"Subprocess element '{subprocess.ElementId}' of process '{process.ProcessId}' carries no bindingRef, so the body stored for it cannot be written back with it. "
                        + "The document does not carry a subprocess's body, so writing it without one would silently empty the subprocess. Send the element with the bindingRef the document GET returned.");
                }

                kept.Add(HandOver(body) with { BindingRef = subprocess.BindingRef });
                KeepEverythingBoundInside(body.ElementId);
            }
        }

        return kept;

        // A nested process's bindings name the subprocess element's id as their process (see BpmnWorkBinding.ProcessId).
        void KeepEverythingBoundInside(string scopeId)
        {
            foreach (var binding in storedBindings.Where(binding => binding.ProcessId == scopeId))
            {
                if (binding is not BpmnWorkBinding.NestedProcess nested)
                {

View on GitHub (pinned to fe9217bdfa)