Portal Community

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 KeyColor (canvas)When FiresSet By
mainGreenNode completed successfullyDefault — NodeExecutionResult.Success()
errorRedUnhandled exception thrownEngine — wraps any thrown exception
timeoutOrangeNode exceeded configured timeoutEngine — cancels node on timeout
customBlue/GrayNode logic returned named keyportKey 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:

  1. Catches the exception and wraps it in an error output: { message, stackTrace, exceptionType }
  2. Stores this error object at ExecutionMemory.nodeOutputs[nodeId]
  3. Routes to the error port — all edges from that port execute
  4. 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"
Best practice: Always connect an error port edge for nodes that call external services. Unhandled errors with no error edge will terminate the workflow execution in a failed state with no compensation path.