Portal Community

The Full Shape

// NodeExecutionResult.cs:82-108
public class NodeExecutionResult
{
    public string OutputPortKey { get; set; } = "main";
    public OutputPortUsageInfo? OutputPort;
    public bool IsSuccess { get; set; } = true;
    public bool IsSkipped { get; set; } = false;
    public bool IsRetry { get; set; } = false;
    public int DurationMs { get; set; } = 0;

    public string? ErrorMessage { get; set; }
    public Exception? Exception { get; set; }

    public INodeResultBranches? OutputBranches { get; set; }

    public Dictionary<string, object> OutputData { get; set; } = new();
    public byte[]? OutputBinary { get; set; }
}
FieldPurpose
OutputPortKeyWhich port the node exited from — "main", "error", a conditional branch name, or "waiting"/"pending" for HIL suspension.
IsSuccessDrives whether OnSuccess or OnError fires, and whether the node's state finalizes as Completed or Failed.
IsSkipped / IsRetryFlags for skip-logic and retry bookkeeping.
DurationMsPopulated from the node's own perf timer, used in the Completed/Error stage report.
ErrorMessage / ExceptionPopulated on failure — never forwarded raw into published events (see Metadata & Events for why).
OutputBranchesA sibling wrapper around OutputData — see Output Branches.
OutputDataThe node's own output — see Output Data.
OutputBinaryRaw binary pass-through (file bytes, images) alongside OutputData.
OutputData and OutputBranches are siblings, not nested This is the single most important structural fact in this whole guide. They are two independent properties on the same object. A JSON path that looks like OutputData.OutputBranches... is not this class's real shape — it's a sign some other code serialized the whole NodeExecutionResult and mistakenly treated it as flat record data. See Pinned Data for exactly this happening.

Where It Gets Created and Reset

A fresh NodeExecutionResult is created at the very start of every single node execution — including every loop iteration — so nothing carries over accidentally between runs of the same node:

// BaseNodeExecutor.Orchestrate.cs:19-24 (Execute method)
executionContext.NodeResult = new NodeExecutionResult
{
    OutputData = new Dictionary<string, object?>()
};

How the Result Flows Back Out

After ExecuteInternalAsync returns, the result propagates up through OnExecuteExecuteProcessElementExecutor.ExecuteAsyncProcessElementExecutionSequencer.ExecuteElementAsync, where its OutputData fields get written into scope (see Execution Memory & Scopes) and its state gets persisted (see Metadata & Events).