Error Handling
retry with backoff, catch for recovery, finally for cleanup, and on_error policies
By default a failing step stops the task. Every loosening of that rule is explicit: retry (try again), catch (recover), finally (always clean up), on_error (downgrade the failure).
Retry with backoff
- name: flaky_call
func: shell
do: ./sometimes-fails.sh
retry:
max_attempts: 4 # total attempts, not extra retries
interval: "200ms" # delay before attempt 2
backoff_rate: 2.0 # 200ms -> 400ms -> 800ms
max_delay: "2s" # cap the growthThese exact field names matter: max_attempts, interval,
backoff_rate, max_delay. Variants like max:/delay:/backoff: are
silently ignored - the step simply will not retry (verified against
v0.7.1).
Two more verified behaviors: a when: condition can restrict which
failures retry, and the engine prints a failure box for every failed
attempt even when a later attempt succeeds - the run still exits 0.
Catch: recovery steps
- name: risky
func: shell
do: exit 1
retry:
max_attempts: 2
interval: "50ms"
catch:
- name: rescue
func: shell
do: echo "recovering..."
finally:
- name: cleanup
func: shell
do: echo "always runs"Order on failure: attempts exhaust -> catch steps run -> finally steps
run. If catch succeeds, the workflow continues (the error is handled).
finally runs on success too.
Protecting a whole task
Since v0.8.0, catch:/finally: attach directly to a task and run with
the same semantics as the step level - catch recovers the task, finally
always runs, and a failing catch keeps the task failed (verified):
tasks:
pipeline:
steps:
- name: work
func: shell
do: ./might-fail.sh
catch:
- name: alert
func: shell
do: 'echo "ALERT: pipeline failed"'
finally:
- name: cleanup
func: shell
do: rm -rf ./tmp-workdirThe step-wrapper pattern (a step with task: plus catch/finally) still
works and remains the way to protect a module task call, since
module-internal task catch/finally is not yet wired:
- name: run_pipeline
task: pipeline
catch:
- name: alert
func: shell
do: 'echo "ALERT: pipeline failed"'on_error policies
- name: best_effort
func: shell
do: ./optional-step.sh
on_error: ignore # also: warn; default is failRun it
orchstep run pipelineWhere to go next
HTTP & APIs - the http function with retries makes robust API automation.