The Element
A ProcessElement is one node instance within a thread. The Element layer is responsible for everything that needs to happen before business logic runs: resolving configuration, evaluating expressions, validating inputs, and dispatching to the correct node executor.
What Is an Element?
In the database, a ProcessElement is a row that says: "there is a node of type X, connected to connector Y, configured with JSON Z, at position K in thread T."
At runtime, the element is represented by a ProcessElementExecutionContext
— a rich object that holds everything needed to execute that specific node instance.
The component that executes an element is the ProcessElementExecutor
— a scoped service that does pre-execution work then hands off to the node executor.
Element Execution Context
| Property | When populated | What it holds |
|---|---|---|
ElementDefinition | Before execution starts | The static definition: type name, timeout, config JSON, connections |
ConnectorID | From the definition | Which credential/service binding this node uses |
ResolvedConfig | After Tier 1 config resolution | The merged 3-layer configuration ready for the executor |
InputData | Set by the orchestrator before element dispatch | Output from upstream nodes mapped into this node's input bag |
OutputData | After executor completes | This node's output, stored on the context for tracing |
Executor | Resolved by INodeExecutorFactory | The concrete executor instance for this node type |
SatelliteNodes | From the definition | Attached helper sub-nodes for this element |
ParentThreadContext | At context creation | Reference to the thread — gives access to ExecutionMemory |
The Pinned Data Short-Circuit
Before any config resolution or executor dispatch, the element executor checks whether the element definition has PinnedData attached. When present, the executor skips all resolution, validation, and business logic — it immediately returns the pinned output as if the node had executed normally. This enables workflow debugging without running real integrations.
The Pre-Execution Pipeline
After the pinned data check, PrepareExecutionAsync runs three stages
in sequence before the executor is dispatched.
Tier 1 — 3-Layer Config Resolution + AtConfigLoad Expressions
The 3-layer configuration merge happens here:
- Layer 1 — Extension config: The node type's template configuration. Cached. Provides universal defaults for this node type across all instances.
- Layer 2 — Connector config: The instance-level configuration from the connector binding. Always fresh. Overrides extension defaults.
- Layer 3 — ProcessElement config: The per-element runtime configuration set in the workflow editor. Applies last.
After merging, only fields with ExpressionPolicy.EvaluationStage == AtConfigLoad
are sent through the expression engine at this stage. Fields like @{env:DATABASE_URL}
or @{secret:ApiKey} do not depend on runtime input data — evaluating them
early keeps the executor clean.
Tier 2 — AtInputReady Expressions
By the time PrepareExecutionAsync is called, the thread orchestrator
has already populated elementContext.InputData with the mapped outputs
from upstream nodes. This makes @{input:...} and
@{output:nodeKey.fieldName} directives resolvable.
Why separate from Tier 1? Tier 1 happens before the input bag exists.
If you try to resolve @{input:employeeId} at config-load time, the input
bag is empty. Tier 2 defers exactly those fields until the input is ready.
If no fields have AtInputReady stage, this entire tier is skipped with no overhead.
Validation
The element is validated before dispatch. Checks:
- An executor was found for this node type
- Required configuration fields are present
- The connector data is valid (if required)
If validation fails, a NodeExecutionResult with IsSuccess = false is returned immediately. The executor is never called.
Executor Dispatch & Timeout
After preparation, the element executor calls
executor.ExecuteAsync(nodeExecutionContext, cancellationToken).
A timeout is enforced via a linked CancellationTokenSource with the element's
configured TimeoutSeconds (default 300s / 5 minutes).
| TimeoutBehavior | What happens |
|---|---|
Error (default) | Route to the node's error output port. Downstream error-handling nodes run. |
Skip | Treat as if the node succeeded. Route to success port. Execution continues. |
Cancel | Stop the entire thread immediately. State → Cancelled. |
Retry | Retry the node once via the retry policy. If that also fails, transition to Failed. |
OnEntry fires in the executor lifecycle, config is resolved,
expressions are evaluated, and InputData is populated.
The executor always starts with a clean, ready-to-use context.