Skip to main content

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.

ParameterDescription
Error CodeA code identifying the error type
Error MessageDescription of the error

When Raise Error executes:

  1. Flow execution stops immediately
  2. The error is propagated to the caller
  3. Any transaction in progress is rolled back
  4. 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.

ParameterDescription
(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.