Error Handling
Error handling steps allow flows to respond to exceptional conditions, stop execution when needed, and communicate errors to callers.
Raise Error
Throws an error that stops flow execution with a message.
| Parameter | Description |
|---|---|
| Error Code | A code identifying the error type |
| Error Message | Description of the error |
When Raise Error executes:
- Flow execution stops immediately
- The error is propagated to the caller
- Any transaction in progress is rolled back
- The error code and message are available to calling flows
Example - Validation Error:
CONDITION: Is Valid Input?
Condition: Input.Amount > 0 AND Input.CustomerId != null
FALSE BRANCH:
RAISE ERROR
Error Code: "INVALID_INPUT"
Error Message: "Amount must be positive and Customer must be specified"
Example - Business Rule Error:
# Check credit limit
RUN LOGIC BLOCK
Logic Block: CheckCreditLimit
→ RemainingCredit
CONDITION: Sufficient Credit?
Condition: Order.TotalAmount <= RemainingCredit
FALSE BRANCH:
RAISE ERROR
Error Code: "CREDIT_EXCEEDED"
Error Message: "Order amount (" + FORMAT(Order.TotalAmount, "C") +
") exceeds available credit (" + FORMAT(RemainingCredit, "C") + ")"
Example - Integration Error:
CALL REST API
Service Connection: PaymentGateway
Operation: ProcessPayment
→ PaymentResult, HttpStatus
CONDITION: Payment Failed?
Condition: HttpStatus >= 400 OR PaymentResult.Status == "declined"
TRUE BRANCH:
RAISE ERROR
Error Code: "PAYMENT_FAILED"
Error Message: "Payment declined: " + PaymentResult.DeclineReason
Halt
Stops the entire flow execution immediately without raising an error.
| Parameter | Description |
|---|---|
| (none) | Halt takes no parameters |
Unlike Raise Error, Halt stops execution gracefully:
- No error is propagated
- Outputs set before Halt are returned
- The transaction is committed (not rolled back)
Example - Early Exit:
# Check if processing is needed
EXECUTE QUERY
Entity: Order
Conditions: OrderId == InputOrderId AND Status == "Processed"
→ ExistingOrder
CONDITION: Already Processed?
Condition: ExistingOrder != null
TRUE BRANCH:
SET OUTPUT
AlreadyProcessed: true
Message: "Order was already processed"
HALT
Example - Conditional Processing:
# Check feature flag
RUN LOGIC BLOCK
Logic Block: GetConfigurationValue
Inputs: { Key: "EnableNewFeature" }
→ FeatureEnabled
CONDITION: Feature Disabled?
Condition: FeatureEnabled == false
TRUE BRANCH:
SET OUTPUT
Skipped: true
Reason: "Feature not enabled"
HALT
# Continue with feature logic...
Error Handling Patterns
Validation Before Processing
Validate all inputs before starting any data modifications:
# 1. Validate all inputs first
CONDITION: Missing Required Fields?
Condition: Input.CustomerId == null OR Input.Amount == null
TRUE BRANCH:
RAISE ERROR
Error Code: "MISSING_REQUIRED"
Error Message: "CustomerId and Amount are required"
CONDITION: Invalid Amount?
Condition: Input.Amount <= 0
TRUE BRANCH:
RAISE ERROR
Error Code: "INVALID_AMOUNT"
Error Message: "Amount must be greater than zero"
# 2. Validate business rules
RUN LOGIC BLOCK
Logic Block: ValidateOrderRules
→ IsValid, ValidationErrors
CONDITION: Business Rules Failed?
Condition: IsValid == false
TRUE BRANCH:
RAISE ERROR
Error Code: "BUSINESS_RULE_VIOLATION"
Error Message: ValidationErrors
# 3. Now safe to proceed with data operations
SAVE ENTITY...
Try-Catch Pattern with Sub-Flows
Handle errors from sub-flows gracefully:
# Main flow calls sub-flow that might fail
RUN LOGIC FLOW
Logic Flow: RiskyOperation
Inputs: { Data: InputData }
→ Success, ErrorMessage, Result
CONDITION: Sub-Flow Failed?
Condition: Success == false
TRUE BRANCH:
# Log the error
SAVE ENTITY
Entity: ErrorLog
Data: {
Operation: "RiskyOperation",
ErrorMessage: ErrorMessage,
InputData: TOSTRING(InputData),
OccurredOn: NOW()
}
# Decide how to proceed
CONDITION: Is Retryable?
Condition: CONTAINS(ErrorMessage, "timeout")
TRUE BRANCH:
# Could implement retry logic
...
FALSE BRANCH:
RAISE ERROR
Error Code: "OPERATION_FAILED"
Error Message: "Operation failed: " + ErrorMessage
FALSE BRANCH:
# Continue with Result
...
Graceful Degradation
Continue processing even when some operations fail:
NEW VARIABLE: Errors (List of String)
NEW VARIABLE: SuccessCount = 0
ITERATOR: Process Each Item
Collection: ItemsToProcess
Item Variable: Item
Steps:
# Try to process
RUN LOGIC FLOW
Logic Flow: ProcessSingleItem
Inputs: { Item: Item }
→ ItemSuccess, ItemError
CONDITION: Item Failed?
Condition: ItemSuccess == false
TRUE BRANCH:
# Record error but continue
UPDATE VARIABLE
Variable: Errors
Set Variable: APPEND(Errors, "Item " + Item.Id + ": " + ItemError)
FALSE BRANCH:
UPDATE VARIABLE
Variable: SuccessCount
Set Variable: SuccessCount + 1
# After processing all items
CONDITION: Any Errors?
Condition: COUNT(Errors) > 0
TRUE BRANCH:
# Log errors but don't fail completely
SAVE ENTITY
Entity: ProcessingLog
Data: {
TotalItems: COUNT(ItemsToProcess),
SuccessCount: SuccessCount,
ErrorCount: COUNT(Errors),
ErrorDetails: JOIN(Errors, "; ")
}
SET OUTPUT
Success: SuccessCount > 0
ProcessedCount: SuccessCount
ErrorCount: COUNT(Errors)
Best Practices
Fail Fast: Validate inputs and check preconditions early, before starting data modifications.
Use Meaningful Error Codes: Error codes should be consistent and identifiable. Use a naming convention like "CATEGORY_SPECIFIC_ERROR".
Provide Helpful Messages: Error messages should explain what went wrong and, if possible, how to fix it.
Log Before Raising: For important errors, create a log record before raising the error so you have an audit trail.
Don't Swallow Errors: If something fails unexpectedly, don't hide it. Either handle it properly or let it propagate.
Consider the Caller: Design your error responses thinking about what the calling flow or system needs to know.
Use Halt for Expected Exits: Use Halt for expected early exits (like "nothing to process"). Use Raise Error for actual problems.
Test Error Paths: Make sure to test what happens when things fail, not just the happy path.