Skip to main content
A Flow Engine run starts at the graph’s root node and follows the connections between nodes until the graph has no more work to do. Along the way, nodes can branch execution, iterate over lists, bail out of a path, or abort the run entirely. Understanding the traversal rules and the error-handling policies is essential for building flows that behave predictably when things go wrong.

Traversal

Execution begins at the root node. For each node reached, the engine runs the node’s operation, then picks the next node by following its outgoing connections. A node is never run twice in a single run. When there are no more reachable nodes to visit, the run finishes. Unlike the Data Engine’s graph model - where reaching an end node terminates evaluation and returns a value - a flow has no single “output” in the same sense. A flow finishes when its graph is exhausted. The run’s result is captured in the token’s persisted assigns and in the logs.

Branching with FlowSwitch

The FlowSwitch node directs execution down one of several alternative paths based on a value computed by an inner graph. Each branch out of the switch is labelled; when the switch runs, the inner graph emits a branch name, and only the matching branch is followed. The other branches are pruned from the traversal and their nodes do not run. This is how a flow reacts to conditions - “if the employee is new, create them in the target system, otherwise update the existing record” becomes a switch with two branches.

Looping with FlowEach

The FlowEach node iterates a list, running its loop body once for each element. The loop body is not a separate, independently-rooted graph - it is the continuation of the main graph from the FlowEach node’s loop port. Because the same token is threaded through every iteration, assigns written inside the loop carry forward rather than reset: the values left in the assigns by the last iteration survive into the main graph after the loop finishes. To collect a value from every iteration instead of keeping only the last, append to a list assign as the loop runs - that is what Flow Assign Append is for. When every element has been visited, execution continues past the FlowEach node along its normal output.

Error handling

When a step run by a FlowAction fails, what happens next is controlled by the action’s on error policy:
  • halt_flow (default): the whole run aborts. No further nodes are executed and the FlowRun is finalised with status aborted.
  • halt_branch: only meaningful inside a loop body - the part of the graph reached from a FlowEach loop port. It stops the current iteration and lets the loop continue with the next element, rather than failing the whole run. Outside a loop there is no surrounding iteration to move on to, so it has nothing to act on.
  • continue: the error is cleared and downstream nodes run as if nothing happened.
The FlowGuard node offers a related mechanism for deliberate bailouts. A guard checks whether a named assign is nil or present and, when it fires, either halts the whole flow or skips the current branch. Unlike a FlowAction failure, a guard fires by design - it is the flow author explicitly saying “if this precondition is not met, do not run the rest of this path.”

Aborting a flow

A flow can also abort itself through a non-recoverable signal on the token. When that signal is set, the run unwinds regardless of which on_error policy is configured on surrounding nodes - no outer action can swallow it. This is distinct from cancellation (which is user-initiated from the editor) and from the halt_flow policy (which is one action’s response to a specific error). In practice, most flows rely on halt_flow as the default failure mode and use halt_branch or continue only where the flow’s design explicitly calls for them.