How-to guide
Handle errors and retries
Retry failed activities, route failures to a handler with onError, and log errors with the error.* fields.
Prerequisites
- A basic workflow ([Build a workflow](build-a-workflow.md))
Per-activity handling#
Every activity can declare an onError block:
"onError": {
"strategy": "fail",
"retries": 2,
"retryDelaySeconds": 5,
"activityId": "a_handler"
}
| Field | Meaning |
|---|---|
strategy |
fail stops the run, continue carries on to the next activity, goto jumps to the activity named in activityId |
retries |
How many times to retry before applying the strategy |
retryDelaySeconds |
Wait between retries |
activityId |
The handler to jump to. Required when the strategy is goto |
Workflow-level handler#
A workflow can declare a catch-all for anything not handled at activity level:
"onError": { "strategy": "goto", "activityId": "a_global_error_handler" }
Logging the failure#
After an onError jump, the target chain can read error.* fields. The canonical first step of an error chain is a log activity that templates them:
{
"id": "a_global_error_handler",
"type": "log",
"inputs": [
{ "name": "level", "value": "error" },
{ "name": "message", "value": "{{error.activityId}} failed: {{error.errorMessage}}" }
],
"next": "a_notify_ops"
}
log writes a real entry to the run's execution log; it is not a notification. Follow it with a messaging or email activity if people should be alerted.
Sub-workflow failures#
When a sub-workflow fails, the parent workflow handles it explicitly through the onError block on the sub_workflow activity.
Long-running work#
Execution state is persisted, so a network interruption does not lose a run. Use delay, approval and external_task for waits that last hours or days rather than holding work open in a script.
Expected result
- Transient failures are retried, and permanent failures reach an explicit handler