Flow Studio
OnSkippedAsync
Fired when the execution router determines a node should not execute — due to conditional branching, a parallel path not being active, or a node being manually disabled. Essential for completeness auditing.
Why Nodes Get Skipped
The workflow engine does not simply execute every node in the graph. It routes execution based on edge conditions and branching logic. Nodes that are not on the active path are skipped rather than executed. The engine still fires OnSkippedAsync for them, allowing subscribers to maintain a complete audit record of every node's outcome.
| SkipReason | When It Occurs |
|---|---|
ConditionalBranchNotTaken | An edge has a condition expression that evaluated to false — this node's branch was not chosen |
ParallelPathNotActive | Node is on a parallel branch that was excluded by a gateway or fork condition |
LoopIterationSkipped | A loop's condition evaluated to skip this iteration — loop body nodes fire Skipped |
ManuallyDisabled | The node was explicitly disabled in the designer (toggle off) |
Completeness Audit Pattern
For compliance workflows it is important to record not just what ran, but what was skipped and why. This pattern ensures every node in every execution has an audit row:
public async Task OnSkippedAsync(NodeExecutionEventArgs args, CancellationToken ct)
{
await _auditRepo.InsertAsync(new NodeExecutionAudit
{
ExecutionId = args.ExecutionId,
NodeId = args.NodeId,
NodeType = args.NodeType,
TenantId = args.TenantId,
Status = AuditStatus.Skipped,
SkipReason = args.SkipReason.ToString(),
Timestamp = DateTimeOffset.UtcNow
}, ct);
}
Metrics for Skip Rates
public Task OnSkippedAsync(NodeExecutionEventArgs args, CancellationToken ct)
{
_metrics.IncrementCounter("node.skipped",
("node_type", args.NodeType),
("skip_reason", args.SkipReason.ToString()),
("process_id", args.ProcessId));
return Task.CompletedTask;
}
Available Data in OnSkipped
| Property | Available? | Notes |
|---|---|---|
args.SkipReason | Yes | Always set, never None |
args.NodeId | Yes | The node that was skipped |
args.NodeType | Yes | TypeCode of the skipped node |
args.Context | Yes (snapshot) | Memory at point of skip decision |
args.DurationMs | null | Node never ran |
args.Result | null | No result from a skipped node |
args.Exception | null | No error from a skipped node |
Skipped vs. Errored: A skipped node is not an error — it is a normal routing outcome. Do not conflate the two in your metrics dashboards. Track skip rates separately from error rates.