Portal Community

Soft Error — Return a Failure Result

Return a failure result when the error is an expected operational condition (e.g. 404 from an external API, validation failure) and you want to route to the node's error output port:

// Soft error — routes to error output port
if (response.StatusCode == 404)
{
    return new NodeExecutionResult
    {
        IsSuccess     = false,
        OutputPortKey = ExecutionConstants.OutputPorts.Error,  // "error"
        ErrorMessage  = $"Resource not found: {url}",
        OutputData    = new Dictionary<string, object>
        {
            { "status",    "error" },
            { "errorCode", "NOT_FOUND" },
            { "url",       url     }
        }
    };
}

Hard Error — Throw an Exception

Throw (or let propagate) an exception when the error is unexpected or unrecoverable. BaseNodeExecutor.ErrorHandler catches it, marks the node as failed, and emits a SignalR failure event. If the node has an error output port, the engine will still attempt to route there:

// Hard error — unexpected condition, let it propagate
var config = mySettings ?? throw new InvalidOperationException(
    "Settings were not initialized before execution.");

// Or throw directly:
throw new ExternalServiceException(
    $"Slack API returned unexpected status {statusCode}: {body}");

Error Handling Flow

  1. Your code throws or returns IsSuccess = false
  2. BaseNodeExecutor.ErrorHandler catches the exception and sets NodeExecutionResult.IsSuccess = false
  3. Engine checks if the node has an error output port (isErrorPort: true in the port definition)
  4. If error port is connected — engine routes to the next node on the error path; execution continues
  5. If error port is not connected — engine marks the execution as Failed and stops

Error Output Port Contract

For a node to support error routing, its NodeType must declare an error output port:

// In NodeType DB record — ports array
{
    "portKey":     "error",
    "portType":    "source",
    "isErrorPort": true,
    "isMainPort":  false,
    "label":       "On Error"
}

// In the frontend renderer
<CustomHandle
    type="source"
    position={Position.Right}
    id="error"
    isErrorPort={true}
    label="On Error"
    style={{ top: '75%' }}
/>

// In the executor — return this portKey on failure
OutputPortKey = "error"   // must match the portKey above

Retry Policy

BaseNodeExecutor reads a retry configuration from the node's settings. If present, it retries ExecuteInternalAsync the specified number of times with exponential backoff before marking the node as failed. The retry count and delay are configured per-node in the Atlas Form using the capability configuration pattern.

Config FieldDefaultBehaviour
maxRetries0Number of retry attempts after first failure
retryDelayMs1000Base delay between retries in ms
retryBackoffMultiplier2.0Exponential backoff multiplier
Prefer Soft Errors for Operational Conditions External APIs returning 4xx/5xx, network timeouts, and validation failures are expected conditions. Return a failure result with a meaningful ErrorMessage and OutputData so the error path in the workflow can inspect the details. Reserve exceptions for programming errors and unexpected states.