Portal Community

NodeExecutionResult Shape

public class NodeExecutionResult
{
    // Output data — stored as $output.{nodeId} in ExecutionMemory
    public Dictionary<string, object> OutputData { get; set; } = new();

    // Which output port the engine should follow next
    // Typical values: "main", "error", "true", "false", or a portKey
    public string OutputPortKey { get; set; } = "main";

    // Whether the node succeeded
    public bool IsSuccess { get; set; } = true;

    // Whether this node was skipped (branch not taken)
    public bool IsSkipped { get; set; } = false;

    // Error message (set when IsSuccess = false)
    public string? ErrorMessage { get; set; }

    // Exception object (captured, not rethrown)
    public Exception? Exception { get; set; }

    // Binary output (e.g. file bytes for download/pass-through)
    public byte[]? OutputBinary { get; set; }
}

Success Result

// Minimal success — engine follows the "main" output port
return new NodeExecutionResult
{
    IsSuccess     = true,
    OutputPortKey = "main",
    OutputData    = new Dictionary<string, object>
    {
        { "statusCode", 200             },
        { "body",       responseBody    },
        { "headers",    responseHeaders }
    }
};

Error Result (Error Port)

// Error — engine follows the "error" output port if one is connected
return new NodeExecutionResult
{
    IsSuccess     = false,
    OutputPortKey = ExecutionConstants.OutputPorts.Error,  // "error"
    ErrorMessage  = "External API returned 500: Internal Server Error",
    OutputData    = new Dictionary<string, object>
    {
        { "status",    "error"    },
        { "errorCode", "API_500"  },
        { "message",   errorText  }
    }
};

Conditional Branch Result

Decision nodes (if-condition, switch) return results where OutputPortKey indicates which branch was taken:

// If-condition node — true branch
return new NodeExecutionResult
{
    IsSuccess     = true,
    OutputPortKey = "true",    // follows the "true" output handle
    OutputData    = new Dictionary<string, object> { { "matched", true } }
};

// Switch node — specific case
return new NodeExecutionResult
{
    IsSuccess     = true,
    OutputPortKey = "case-premium",  // matches a portKey on the switch node
    OutputData    = new Dictionary<string, object> { { "tier", "premium" } }
};

Skip Result

A skipped result means the node ran but produced no meaningful output. The engine counts it as completed and continues without routing:

// Skip — node execution was a no-op (e.g. loop has no items)
return new NodeExecutionResult
{
    IsSuccess     = true,
    IsSkipped     = true,
    OutputPortKey = "main",
    OutputData    = new Dictionary<string, object>()
};

OutputPortKey Convention

OutputPortKeyWhen to Use
"main"Success path — most nodes (default)
"error"Error path — only if node has an error output port configured
"true" / "false"If-condition branches
Custom portKeySwitch branches, multi-output nodes — must match ProcessElementPort.portKey
OutputData Becomes $output.{nodeId} Everything in OutputData is accessible downstream via $output.{nodeId}.{field} expressions. Keep keys descriptive and flat where possible. Nested objects are supported but make expressions more verbose.