on_error
Control how errors are handled during module execution.
Syntax
result = Module(args) with on_error: <strategy>
Type: Strategy enum (propagate, skip, log, wrap)
Description
The on_error option determines what happens when a module call fails. Unlike fallback which provides a specific value, on_error defines a general error handling strategy.
With skip, failures return the zero value for the return type (0 for Int, "" for String, etc.). Ensure downstream code can handle these sentinel values without misinterpreting them as valid results.
Use on_error: log, fallback: value to get both visibility (logged errors) and graceful degradation (specific fallback value). The log strategy alone only provides zero values.
Strategies
propagate (default)
Re-throw the error to the caller. This is the default behavior when no error handling is specified.
result = RiskyOperation(data) with on_error: propagate
Errors bubble up to be handled by the calling context.
skip
Return a zero/default value for the type and continue execution.
count = CountItems(list) with on_error: skip
# Returns 0 (zero value for Int) on failure
Zero values by type:
Int→0Double→0.0String→""Boolean→falseList[T]→[]Optional[T]→None
log
Log the error and return a zero value. Combines logging with graceful degradation.
data = ProcessData(input) with on_error: log
Logs: [ProcessData] failed: <error message>. Skipping.
wrap
Wrap the result in an Either type for downstream handling.
result = UncertainOperation(input) with on_error: wrap
# Returns Either[Error, Value]
Downstream code can then handle the error explicitly:
processed = when result.isRight then process(result.right) else handleError(result.left)
Examples
Skip Failing Items in a Pipeline
in items: List[Record]
# Process each item, skipping failures
processed = items.map(item => Transform(item) with on_error: skip)
out processed
Log and Continue
# Log any failures but continue with default values
enriched = EnrichData(data) with on_error: log, retry: 2
Wrap for Explicit Handling
result = ExternalService(request) with on_error: wrap
# Handle the wrapped result
output = when result.isRight
then result.right
else { error: result.left.message, fallback: true }
out output
on_error vs fallback
| Aspect | on_error | fallback |
|---|---|---|
| Value | Zero/default for type | Specific expression |
| Flexibility | Fixed strategies | Any expression |
| Type | Must match return type | Must match return type |
| Use case | General handling | Specific default value |
They can be combined, but fallback takes precedence:
# fallback is used for the value, on_error: log adds logging
result = Operation(x) with on_error: log, fallback: defaultValue
Related Options
Best Practices
- Use
propagatewhen errors must be handled upstream - Use
skipfor non-critical operations in pipelines - Use
logwhen you need visibility into failures - Use
wrapfor explicit error handling in code - Combine with
retryto attempt recovery first