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

  1. Set the join activity's Mode to a valid FlowJoinMode value: WaitAll, WaitAllActive, or WaitAny.
  2. Migrate workflow definitions from removed enum members to the current FlowJoinMode set.
  3. Avoid casting arbitrary ints to FlowJoinMode; parse with Enum.TryParse and validate.
  4. 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

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


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)