Portal Community

How Output Gets Written

Executors never call SetNodeOutput directly. They return a NodeExecutionResult, and BaseNodeExecutor writes the output to memory after the executor completes.

// BaseNodeExecutor.cs (simplified write path)
var result = await ExecuteAsync(ctx, ct);

if (result.IsSuccess)
{
    // Write output to the shared nodeOutputs map
    ctx.ExecutionMemory.SetNodeOutput(ctx.NodeId, result.Output);

    // Also persist pinnedData if non-null (separate concern — see Guide30)
    if (result.PinnedData is not null)
        await _pinnedDataService.SaveAsync(ctx.ProcessId, ctx.NodeId, result.PinnedData, ct);
}

Key and Value Semantics

PropertyDetail
KeyThe nodeId string — e.g. "node-abc". Set by the workflow designer in Flow Studio.
Value typeobject? — any JSON-serializable value. Typically an anonymous object, POCO, primitive, or null.
OverwriteLast write wins. If a node runs twice (e.g., in a retry loop), each execution overwrites the previous output.
Missing keyGetNodeOutput returns null if the nodeId is not in the map — safe to handle with null-check.

Type Safety

// Option 1 — untyped (use when type is unknown)
var raw = ctx.ExecutionMemory.GetNodeOutput("data-transform-node");

// Option 2 — typed cast (most common)
var result = ctx.ExecutionMemory.GetNodeOutput<TransformResult>("data-transform-node");
// Returns null if key missing OR if the stored value is not castable to TransformResult

// Option 3 — primitive types use the untyped overload
var count = (int?)ctx.ExecutionMemory.GetNodeOutput("counter-node") ?? 0;

What Can Be Stored

Value TypeSupported?Notes
Anonymous objectYesCommon for short-lived inter-node data
POCO classYesPrefer for typed downstream reads
string, int, bool, decimalYesUse untyped GetNodeOutput and cast
List<T> or T[]YesArrays and lists are fully supported
nullYesWritten to map as null — GetNodeOutput will return null
Non-serializable (streams, sockets)NoWill fail during HIL serialization (see Guide31/06)

Naming Convention for nodeId

nodeIds are set by the workflow designer in Flow Studio when placing a node on the canvas. By default they are machine-generated (e.g., node-1, node-2), but designers should rename nodes to meaningful IDs when cross-node data access is needed.

// Good — executor reads from a meaningfully named node
var customerData = ctx.ExecutionMemory.GetNodeOutput<Customer>("fetch-customer");

// Fragile — if the nodeId changes in the workflow, this breaks
var customerData = ctx.ExecutionMemory.GetNodeOutput<Customer>("node-3");
Document your nodeId dependencies. If your executor reads from a specific upstream node by ID, document this in the executor's XML summary or README so workflow designers know which node must be named that way. Breaking the nodeId contract is a silent runtime error — the executor gets null with no error.