Output Ports
The four standard port types — main, error, timeout, and conditional — how they appear on the canvas, and how the edge router uses them to direct execution flow.
What Is a Port?
A port is a named connection point on a node where edges can originate. The edge router reads the portKey from NodeExecutionResult and fires all edges that are registered to that port. Edges not connected to the fired port are ignored for this execution.
Standard Port Types
| Port Key | Color (canvas) | When Fires | Set By |
|---|---|---|---|
main | Green | Node completed successfully | Default — NodeExecutionResult.Success() |
error | Red | Unhandled exception thrown | Engine — wraps any thrown exception |
timeout | Orange | Node exceeded configured timeout | Engine — cancels node on timeout |
| custom | Blue/Gray | Node logic returned named key | portKey in Success() |
Port Declaration in the Frontend
Custom ports are declared in the React node component using CustomHandle. The handle's id property must match the portKey returned by the executor:
// packages/flow-studio-designer/src/components/Handles/CustomHandle.tsx
interface CustomHandleProps {
id: string; // must match portKey from executor
label: string; // displayed on canvas
type: "source" | "target";
position: Position;
color?: string;
}
// Example: A decision node with approved/rejected ports
export function DecisionNode({ data }: NodeProps) {
return (
<div className="node decision-node">
<NodeLabel>{data.label}</NodeLabel>
<CustomHandle id="approved" label="Approved" type="source" position={Position.Right} color="#22c55e" />
<CustomHandle id="rejected" label="Rejected" type="source" position={Position.Bottom} color="#ef4444" />
</div>
);
}
Edge Router Logic
The backend EdgeRouter selects edges to follow based on the fired port key:
// ProcessEngine/EdgeRouter.cs (simplified)
public IEnumerable<WorkflowEdge> GetEdgesForPort(
string nodeId,
string portKey,
IEnumerable<WorkflowEdge> allEdges)
{
return allEdges.Where(edge =>
edge.SourceNodeId == nodeId &&
edge.SourcePortKey == portKey &&
EvaluateCondition(edge.Condition));
}
Error Port Behavior
When a node throws an unhandled exception, the engine:
- Catches the exception and wraps it in an error output:
{ message, stackTrace, exceptionType } - Stores this error object at
ExecutionMemory.nodeOutputs[nodeId] - Routes to the
errorport — all edges from that port execute - If no edges are connected to the error port, the entire execution fails
// Accessing error details in the error handler node
$output.failedNode.message // "Connection refused"
$output.failedNode.exceptionType // "System.Net.Http.HttpRequestException"
Timeout Port
Set a node timeout in the node inspector panel (in seconds). If the node's ExecuteAsync does not return within the timeout, the engine cancels the task and fires the timeout port with output:
$output.slowNode.timedOutAfterMs // 30000
$output.slowNode.nodeId // "slowNode"