Skip to main content
Every workflow step decides what happens when it fails. By default a failure stops the whole run — but you can also continue past it or retry. The simplest failing pipeline: on_error="stop" (the Task default) aborts the run the moment a step raises.

How it Works

A step raises, on_error is consulted, and the run either aborts or keeps going — but the final status reflects the failure either way.

Which mode when?

Pick the mode that matches how much a single failure should affect the run.
  • Stop → data integrity matters; one failure means the whole run is wrong.
  • Continue → batch processing; partial results are useful.
  • Retry → transient failures like network blips or rate limits.

on_error Options

Retry Configuration

Set max_retries on flaky steps. Retries use exponential backoff of 2 ** (attempt - 1) seconds between attempts.
  • max_retries — how many extra attempts before the step is considered failed (default 3).
  • is_retryable — set False on your exception class to short-circuit retries for known non-retryable failures.
  • Backoff between attempts is 2 ** (attempt - 1) seconds.

Guardrail Failures

A guardrail that never validates after exhausting its retries is treated like an exception — it surfaces as step_error and follows the same on_error rules. See Guardrails for validator configuration.

Errors in Nested Patterns

As of PR #4194, the same rules apply inside every nested pattern. A stopping step propagates out of the pattern and aborts the enclosing workflow.
Sequential and parallel iterations both honour on_error. A stopping iteration halts the enclosing workflow, not just the loop.
The three on_failure modes now behave differently (see the table below).
A stopping step inside a conditional branch stops the workflow, not just the branch.
A stopping step inside the matched route stops the workflow.
A stopping iteration ends the repeat loop and the workflow.

on_error="continue" keeps running

The exception text is never fed to the next step. A downstream step receives the last successful output (or the initial input), never "Error: boom".

Reading the Result

Inspect result["status"] and each step’s error field to find what failed.
You can also read workflow.step_statuses for a per-step status map after the run.

parallel(on_failure=...) Modes

In every mode the whole run is marked failed. With partial_ok, the failing branch is recorded as {"output": None, "error": str(e)} — the exception text is not folded into the branch output.

Behavior Change

Runs that previously reported completed while containing a failed step now correctly report failed. If you built on the old (broken) behaviour you may see “new” failures appear — this is intentional, the old behaviour was silent data corruption. See PR #4194.

Best Practices

Use on_error="stop" unless you have a concrete reason to continue. It keeps a failed run from producing partially-correct output.
Prefer per-item try/except inside your handler when you want fine-grained control inside loop(parallel=True) — convert an expected failure into a valid StepResult the rest of the run can consume.
Set max_retries on steps that hit the network or LLM rate limits rather than wrapping them in repeat.
Never feed a previous step’s output to a downstream step without checking result["status"] first.

Workflows

Build multi-step workflows with AgentFlow

Nested Workflows

Combine loops, parallel, and routing patterns

Guardrails

Validate step output and retry on failed checks

Workflow Manager API

API reference for step statuses and error handling