This document explains how workflows execute other workflows inline through the Workflow block (BlockType.WORKFLOW). It covers call chain tracking for cycle detection, depth limits for resource management, child workflow context propagation, error handling, and how nested executions appear in the terminal UI.
For information about loop and parallel subflow execution, see 3.5 Loop & Parallel Execution For human-in-the-loop pause/resume mechanics, see 3.14 Human-in-the-Loop & Paused Executions
The WorkflowBlockHandler executes child workflows inline by creating a sub-executor with an isolated execution context. Child workflows are loaded from either the draft state or deployed state depending on the parent execution mode.
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts38-61
Diagram: Workflow Block Handler Execution Flow
The handler implements both execute() (apps/sim/executor/handlers/workflow/workflow-handler.ts46-51) and executeWithNode() (apps/sim/executor/handlers/workflow/workflow-handler.ts54-61) methods. Both delegate to executeCore() (apps/sim/executor/handlers/workflow/workflow-handler.ts63-258), with executeWithNode() receiving additional nodeMetadata for iteration context propagation.
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts42-61 apps/sim/executor/handlers/workflow/workflow-handler.ts63-258
Diagram: Child Workflow Loading Strategy
The executeCore() method branches based on ctx.isDeployedContext. For deployed mode, it first calls checkChildDeployment() (apps/sim/executor/handlers/workflow/workflow-handler.ts383-400) to verify the child workflow has an active deployment. For draft mode, it loads directly via loadChildWorkflow() (apps/sim/executor/handlers/workflow/workflow-handler.ts326-381).
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts94-105 apps/sim/executor/handlers/workflow/workflow-handler.ts326-459
The platform tracks workflow call chains to prevent infinite recursion. Each workflow execution includes a callChain array in its context, which is used to validate the nesting depth before execution begins.
Diagram: Call Chain Validation Flow
The validation occurs within executeCore(). The buildNextCallChain() function (apps/sim/executor/handlers/workflow/workflow-handler.ts83) prepares the new chain, and validateCallChain() (apps/sim/executor/handlers/workflow/workflow-handler.ts84) checks if the chain exceeds depth limits.
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts83-90 apps/sim/lib/execution/call-chain.ts22-27
| Constant | Value | Purpose |
|---|---|---|
MAX_CALL_CHAIN_DEPTH | 25 | Maximum workflow nesting depth before blocking execution |
Sources: apps/sim/executor/handlers/workflow/workflow-handler.test.ts134-136
The ChildWorkflowContext structure propagates metadata about the parent-child relationship through the execution stack, allowing the engine to track depth and parentage.
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts186-191 apps/sim/executor/execution/types.ts12-17
Diagram: Child Context Depth Propagation
The context is created when instantiating the child executor and increments the depth counter based on the parent's current depth (apps/sim/executor/handlers/workflow/workflow-handler.ts143).
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts143 apps/sim/executor/handlers/workflow/workflow-handler.ts186-191
Server-Sent Events (SSE) callbacks for block lifecycle events (onBlockStart, onBlockComplete, onStream) are conditionally propagated to child workflows based on depth limits to prevent event storms.
| Depth | Callbacks Propagated | Reason |
|---|---|---|
| 0 (parent) | Yes | Top-level execution |
| 1-3 | Yes | Controlled visibility for child levels |
| 4+ | No | Exceeds DEFAULTS.MAX_SSE_CHILD_DEPTH |
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts144-152
Diagram: SSE Callback Propagation Decision
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts143-152
Each workflow block invocation generates a unique instanceId. This ID is critical for correlating child block events with a specific workflow block execution, especially in loops where the same block may run multiple times.
Diagram: Instance ID Correlation Sequence
The instanceId is generated using generateId() (apps/sim/executor/handlers/workflow/workflow-handler.ts81). The onChildWorkflowInstanceReady callback fires before child execution begins (apps/sim/executor/handlers/workflow/workflow-handler.ts159-164), allowing the UI to prepare the nesting structure.
Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts81 apps/sim/executor/handlers/workflow/workflow-handler.ts159-165
Child workflow execution logs are aggregated into the parent's trace spans to provide a unified debugging view.
Diagram: Trace Span Aggregation Pipeline
captureChildWorkflowLogs builds the hierarchy from raw child logs (apps/sim/executor/handlers/workflow/workflow-handler.ts464-495).processChildWorkflowSpans removes synthetic workflow wrappers to avoid redundant "Workflow Execution" nodes (apps/sim/executor/handlers/workflow/workflow-handler.ts520-543).transformSpanForChildWorkflow tags spans with the child workflow name and flags them as nested (apps/sim/executor/handlers/workflow/workflow-handler.ts497-518).Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts464-543 apps/sim/lib/logs/execution/trace-spans/trace-spans.ts49-66
Child workflow failures are caught and mapped back to the parent workflow block.
mapChildOutputToParent function converts a child ExecutionResult into a parent-compatible BlockOutput (apps/sim/executor/handlers/workflow/workflow-handler.ts420-459).ChildWorkflowError or re-thrown with context so the parent BlockExecutor can route it to the error port (apps/sim/executor/handlers/workflow/workflow-handler.ts444-458).Sources: apps/sim/executor/handlers/workflow/workflow-handler.ts420-459 apps/sim/executor/errors/child-workflow-error.ts1-10
Nested workflow execution enables modular workflow composition with:
Refresh this wiki