elsa-workflows/elsa-core · error · Exception
Target context activity must be this flowchart
Error message
Target context activity must be this flowchart
What it means
ProcessChildCompletedAsync is a completion callback that must be invoked with an ActivityExecutionContext whose Activity is the Flowchart instance itself. If the context belongs to a different activity, the internal counter/bookkeeping state would be corrupted, so the code throws an InvalidOperationException immediately. This is an internal invariant check, not a user-facing validation.
Solutions
- Ensure the completion callback is registered on the flowchart's own ActivityExecutionContext, not a child's.
- If subclassing Flowchart, call the public/protected scheduling APIs instead of invoking the private handler with a foreign context.
- Re-check that activities are scheduled with scheduleWorkOptions tied to the flowchart context.
- Update Elsa packages together (core and flows) if a mixed-version runtime mismatches callback contexts.
Example fix
// before
scheduleWorkOptions = new() { CompletionCallback = OnChildCompletedAsync }; // callback captures child context
// after
flowchartContext.ScheduleActivity(activity, OnChildCompletedAsync); // Elsa binds the flowchart context as the first parameter Defensive patterns
Strategy: type-guard
Validate before calling
if (context.Activity is not Flowchart) throw new InvalidOperationException("Completion callback must be bound to the Flowchart context."); Type guard
static bool IsFlowchartContext(ActivityExecutionContext ctx) => ctx.Activity is Flowchart;
Try / catch
try { await ProcessChildCompletedAsync(flowchartContext, completedActivity, completedActivityContext, outcomes); }
catch (InvalidOperationException ex) when (ex.Message == "Target context activity must be this flowchart")
{
logger.LogError(ex, "Flowchart completion callback invoked with mismatched activity context.");
} Prevention
- Always schedule child activities through the flowchart's ActivityExecutionContext so completion callbacks bind correctly.
- Do not reuse flowchart completion delegates for other composite activities.
- Keep Elsa.Workflows.Core packages on a single version across the app.
When it happens
Trigger: A child activity's Completed/CompletedCallback resolves to the ProcessChildCompletedAsync handler while the callback context was captured for a different activity; typically caused by custom Flowchart subclasses or reused delegates wiring OnChildCompletedCounterBasedLogicAsync to the wrong ActivityExecutionContext.
Common situations: Custom flowchart-like composite activities copying Elsa's Flowchart sample code but passing the wrong execution context to the completion callback; version drift where Flowchart internals changed but derived classes call the private handler directly via reflection.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Activity is not reachable from the flowchart graph. Unable…
- Unsupported FlowJoinMode
- Source label ' ' not found in flowchart
- Target label ' ' not found in flowchart
- Activity context is not a flowchart.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/8a2de56b4f56415d.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.Counters.cs:125
return rootActivity;
}
private FlowGraph GetFlowGraph(ActivityExecutionContext context)
{
// Store in TransientProperties so FlowChart is not persisted in WorkflowState
return context.TransientProperties.GetOrAdd(GraphTransientProperty, () => new FlowGraph(Connections, GetStartActivity(context)));
}
private FlowScope GetFlowScope(ActivityExecutionContext context)
{
return context.GetProperty(ScopeProperty, () => new FlowScope());
}
private async ValueTask ProcessChildCompletedAsync(ActivityExecutionContext flowchartContext, IActivity completedActivity, ActivityExecutionContext completedActivityContext, Outcomes outcomes)
{
if (flowchartContext.Activity != this)
{
throw new("Target context activity must be this flowchart");
}
// If the completed activity's status is anything but "Completed", do not schedule its outbound activities.
if (completedActivityContext.Status != ActivityStatus.Completed)
{
return;
}
// If the complete activity is a terminal node, complete the flowchart immediately.
if (completedActivity is ITerminalNode)
{
await flowchartContext.CompleteActivityAsync();
return;
}
// Schedule the outbound activities
var flowGraph = GetFlowGraph(flowchartContext);
var flowScope = GetFlowScope(flowchartContext);View on GitHub (pinned to fe9217bdfa)