elsa-workflows/elsa-core · error · Exception
Unsupported FlowJoinMode
Error message
Unsupported FlowJoinMode: {mode} What it means
Flowchart join behavior is selected via the FlowJoinMode enum (WaitAll, WaitAllActive, WaitAny). When scheduling an outbound activity after a completion, MaybeScheduleOutboundActivityAsync switches on the joined activity's FlowJoin mode; an unknown or out-of-range value hits the discard arm and throws InvalidOperationException. This protects against silently applying wrong join semantics.
Solutions
- Set the join activity's Mode to a valid FlowJoinMode value: WaitAll, WaitAllActive, or WaitAny.
- Migrate workflow definitions from removed enum members to the current FlowJoinMode set.
- Avoid casting arbitrary ints to FlowJoinMode; parse with Enum.TryParse and validate.
- Catch the exception during scheduling and fall back to a default join mode if configurations are untrusted.
Example fix
// before
var join = new FlowJoin { Mode = (FlowJoinMode)7 };
// after
var join = new FlowJoin { Mode = Enum.IsDefined(typeof(FlowJoinMode), mode) ? (FlowJoinMode)mode : FlowJoinMode.WaitAny }; Defensive patterns
Strategy: validation
Validate before calling
if (!Enum.IsDefined(typeof(FlowJoinMode), join.Mode))
throw new InvalidOperationException($"Join '{join.Id}' has unsupported FlowJoinMode '{join.Mode}'."); Type guard
static bool IsValidJoinMode(FlowJoinMode mode) => mode is FlowJoinMode.WaitAll or FlowJoinMode.WaitAllActive or FlowJoinMode.WaitAny;
Try / catch
try { await MaybeScheduleOutboundActivityAsync(...); }
catch (InvalidOperationException ex) when (ex.Message.StartsWith("Unsupported FlowJoinMode:"))
{
logger.LogError(ex, "Workflow uses an unknown join mode; migrate the definition.");
} Prevention
- Only assign named FlowJoinMode members, never raw integer casts.
- Migrate definitions when upgrading Elsa versions if enum members changed.
- Validate join modes at workflow import time.
When it happens
Trigger: A FlowJoin activity (or the flowchart's join resolution) has a Mode value not present in the FlowJoinMode enum — e.g. an enum cast from an int that has no named member, a stale serialized mode from an older Elsa version, or default(FlowJoinMode) when 0 is not a defined member.
Common situations: Upgrading workflows authored on a version whose enum members were renamed/removed; deserializing definitions from JSON where the mode string failed to map; custom code casting raw integers into FlowJoinMode.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Target context activity must be this flowchart
- Activity is not reachable from the flowchart graph. Unable…
- Interval expression type
- Unsupported console stream value
- The console log stream filter has an unsupported numeric…
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/25f9798e614744b7.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.Counters.cs:261
{
// Implicit join case - treat as WaitAllActive
return FlowJoinMode.WaitAllActive;
}
}
/// <summary>
/// Schedules a join activity based on inbound connection statuses.
/// </summary>
private static async ValueTask<bool> MaybeScheduleOutboundActivityAsync(FlowGraph flowGraph, FlowScope flowScope, ActivityExecutionContext flowchartContext, ActivityExecutionContext? completedActivityContext, Connection outboundConnection, IActivity outboundActivity, ActivityCompletionCallback completionCallback)
{
FlowJoinMode mode = await GetMergeModeAsync(flowchartContext, outboundActivity);
return mode switch
{
FlowJoinMode.WaitAll => await MaybeScheduleWaitAllActivityAsync(flowGraph, flowScope, flowchartContext, completedActivityContext, outboundActivity, completionCallback),
FlowJoinMode.WaitAllActive => await MaybeScheduleWaitAllActiveActivityAsync(flowGraph, flowScope, flowchartContext, completedActivityContext, outboundActivity, completionCallback),
FlowJoinMode.WaitAny => await MaybeScheduleWaitAnyActivityAsync(flowGraph, flowScope, flowchartContext, completedActivityContext, outboundConnection, outboundActivity, completionCallback),
_ => throw new($"Unsupported FlowJoinMode: {mode}"),
};
}
/// <summary>
/// Determines whether to schedule an activity based on the FlowJoinMode.WaitAll behavior.
/// If all inbound connections were visited, it checks if they were all followed to decide whether to schedule or skip the activity.
/// </summary>
private static async ValueTask<bool> MaybeScheduleWaitAllActivityAsync(FlowGraph flowGraph, FlowScope flowScope, ActivityExecutionContext flowchartContext, ActivityExecutionContext? completedActivityContext, IActivity outboundActivity, ActivityCompletionCallback completionCallback)
{
if (!flowScope.AllInboundConnectionsVisited(flowGraph, outboundActivity))
// Not all inbound connections have been visited yet; do not schedule anything yet.
return false;
if (flowScope.AllInboundConnectionsFollowed(flowGraph, outboundActivity))
// All inbound connections were followed; schedule the outbound activity.
return await ScheduleOutboundActivityAsync(flowchartContext, completedActivityContext, outboundActivity, completionCallback);
else
// No inbound connections were followed; skip the outbound activity.View on GitHub (pinned to fe9217bdfa)