elsa-workflows/elsa-core · error · InvalidOperationException
The specified activity is not part of the workflow.
Error message
The specified activity is not part of the workflow.
What it means
Thrown by WorkflowExecutionContextSchedulerStrategy.Schedule when the requested ActivityNode's underlying Activity is not in the workflow execution context's NodeActivityLookup, i.e., the node does not belong to the currently executing workflow graph. This is the main-scheduler counterpart of the background-execution check and guards the scheduler from operating on foreign activities.
Solutions
- Obtain the ActivityNode from the current context graph (e.g., context.FindNodeById / NodeActivityLookup) rather than caching or constructing nodes manually.
- Rebuild any cached node references after the workflow definition is reloaded or the instance is resumed.
- Ensure composite children are registered in the graph so their nodes exist in this context before scheduling.
Example fix
// before
var node = new ActivityNode(myActivity); // foreign to this workflow
context.Scheduler.ScheduleItem(new ActivityWorkItem(node.Id, ...));
// after
var node = context.NodeActivityLookup[myActivity] ?? context.FindNodeById(myActivity.Id);
if (node == null) throw new InvalidOperationException("Activity not in current workflow");
await context.ScheduleActivityAsync(myActivity, onCompleted); Defensive patterns
Strategy: validation
Validate before calling
if (!context.NodeActivityLookup.ContainsKey(activityNode.Activity))
throw new InvalidOperationException("ActivityNode does not belong to this workflow context graph."); Type guard
bool NodeBelongsToContext(WorkflowExecutionContext ctx, ActivityNode n) => ctx.NodeActivityLookup.ContainsKey(n.Activity);
Try / catch
try
{
var workItem = strategy.Schedule(context, node, owner, options);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("not part of the workflow"))
{
logger.LogWarning(ex, "Foreign node {NodeId} rejected by scheduler", node.NodeId);
} Prevention
- Always obtain ActivityNode instances from the live context graph, never from caches or manual construction.
- Invalidate cached nodes whenever a workflow definition reloads or an instance resumes.
- Use context.ScheduleActivityAsync helpers that resolve nodes internally.
When it happens
Trigger: Calling context.Schedule / ScheduleActivity with an ActivityNode built from another workflow's graph, a node from a stale graph after re-loading/rebuilding the workflow, or a node constructed manually (new ActivityNode(activity)) for an activity not committed to this context.
Common situations: Custom scheduler integrations that cache ActivityNodes across workflow restarts, composite activities scheduling nodes from a different composite instance, and hot-reloaded definitions where old node references linger.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- StateMachine transitions cannot share a Trigger activity in…
- The specified activity is not part of the workflow.
- A conversation ID is required. (Parameter 'conversation')
- A conversation user ID is required. (Parameter…
- A conversation ID is required. (Parameter 'conversation')
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/095199158cee65a0.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Services/WorkflowExecutionContextSchedulerStrategy.cs:14
using Elsa.Workflows.Models;
using Elsa.Workflows.Options;
namespace Elsa.Workflows;
/// <inheritdoc />
public class WorkflowExecutionContextSchedulerStrategy : IWorkflowExecutionContextSchedulerStrategy
{
/// <inheritdoc />
public ActivityWorkItem Schedule(WorkflowExecutionContext context, ActivityNode activityNode, ActivityExecutionContext owner, ScheduleWorkOptions? options = null)
{
// Validate that the specified activity is part of the workflow.
if (!context.NodeActivityLookup.ContainsKey(activityNode.Activity))
throw new InvalidOperationException("The specified activity is not part of the workflow.");
var scheduler = context.Scheduler;
if (options?.PreventDuplicateScheduling == true)
{
// Check if the activity is already scheduled for the specified owner.
var existingWorkItem = scheduler.Find(x => x.Activity.NodeId == activityNode.NodeId && x.Owner == owner);
if (existingWorkItem != null)
return existingWorkItem;
}
var activity = activityNode.Activity;
var tag = options?.Tag;
// Use explicit SchedulingActivityExecutionId from options, or fall back to owner context.
var schedulingActivityExecutionId = options?.SchedulingActivityExecutionId ?? owner.Id;
View on GitHub (pinned to fe9217bdfa)