elsa-workflows/elsa-core · error · InvalidOperationException

BPMN element ' ' binds work ' ', which activity ' ' does…

Error message

BPMN element '{start.ElementId}' binds work '{start.BindingRef}', which activity '{process.Id}' does not map to a child activity.

What it means

BpmnCommandApplier.StartWorkAsync resolves a StartWork command's BindingRef to a child activity of the hosting process; if FindWorkActivity returns null the binding cannot be mapped and an InvalidOperationException is thrown naming the element, binding ref, and process id. This indicates the command batch references work that does not exist in the process activity tree.

Solutions

  1. Rebuild/re-import the BPMN model so the command batch and activity tree refer to the same revision.
  2. Verify the BindingRef in the error message exists as an element id in the BPMN document.
  3. Ensure the process definition containing the bound element is the one actually deployed/executed.
Defensive patterns

Strategy: validation

Validate before calling

foreach (var c in commands.OfType<BpmnHostCommand.StartWork>())
    if (process.FindWorkActivity(c.BindingRef) is null) throw new InvalidOperationException($"BindingRef '{c.BindingRef}' missing from process '{process.Id}'.");

Try / catch

try { await applier.ApplyAsync(context, commands); }
catch (InvalidOperationException ex) when (ex.Message.Contains("does not map to a child activity")) { log.LogError(ex, "Stale BPMN binding"); /* re-import model and retry */ }

Prevention

When it happens

Trigger: Applying a StartWork command whose BindingRef does not correspond to any child activity of the current process (process.FindWorkActivity returns null).

Common situations: Stale command batches produced against a different process revision; model edits that removed or renamed the bound activity; id mismatch between document and compiled activity tree.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — 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/38520b21b55cad5d. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Bpmn/Hosting/BpmnCommandApplier.cs:77

                    break;
                case BpmnHostCommand.SignalEnclosingScope signal:
                    await SignalEnclosingScopeAsync(signal);
                    break;
                default:
                    // The command hierarchy is closed, so this can only be reached by a library version that added a
                    // command this host has never heard of. Refusing is the only honest answer: silently skipping it
                    // would run a different process than the one the interpreter decided on.
                    throw new NotSupportedException($"The BPMN host command '{command.GetType().Name}' is not supported by this host.");
            }

            memory.SaveWork();
        }
    }

    private async ValueTask StartWorkAsync(BpmnHostCommand.StartWork start)
    {
        var activity = process.FindWorkActivity(start.BindingRef)
                       ?? throw new InvalidOperationException(
                           $"BPMN element '{start.ElementId}' binds work '{start.BindingRef}', which activity '{process.Id}' does not map to a child activity.");

        // The rule that a nested scope registers no start triggers is enforced by ApplyAsync's pre-scan, before any
        // command in the batch is applied — not here, where earlier commands in the same batch could already have
        // been applied and persisted.
        var workflowExecutionContext = scopeContext.WorkflowExecutionContext;

        // The child's context is created up front so that this scope has its id before the child ever runs, and can
        // key the unit of work on it. The alternative — recognising the child by ActivityExecutionContext.Tag — is
        // unsound across nested scopes, because the completion-callback dispatch rewrites the receiving context's Tag.
        var childContext = await workflowExecutionContext.CreateActivityExecutionContextAsync(activity, new ActivityInvocationOptions
        {
            Owner = scopeContext,
            Variables = BuildIterationVariables(start.IterationScope),
            SchedulingActivityExecutionId = scopeContext.Id
        });

        // The correlation is opaque interpreter state that must travel with the work and, when the work is a nested

View on GitHub (pinned to fe9217bdfa)