# Error Handling & Retries

> Build resilient workflows using automated retries and fallback logic.

Error Handling & Retries answers: **How should a Step retry, and where should the run go after retries are exhausted?** Both controls live in the Step's **Test & Debug** tab. For a failure that already happened, start in [Activity](/manage/workspace-settings/activity) and inspect the affected [Step execution](/build/core-concepts/executions).

Retries and error routing are off by default, so an untouched Step fails the whole run the first time it fails. This page covers both controls and the failures that are never retried.

## Retry on Fail

Any step can retry itself before giving up. Open the step, go to the **Test & Debug** tab, and turn on **Retry on fail**.

> **Retries are off by default.** Unless you turn this on, a step that fails
> once fails the whole run. Turn it on for anything that talks to a third-party
> API, where a transient failure is normal.

| Setting                | Default | Range        |
| ---------------------- | ------- | ------------ |
| **Max retries**        | 10      | 0–10         |
| **Wait between tries** | 60 s    | 0–60 seconds |

**The defaults are the ceiling.** Turn the toggle on and leave the fields alone and you have asked for ten retries a minute apart: ten minutes of a run held open. Most third-party APIs recover much faster than that, so it is worth lowering both before you save.

**Max retries counts retries, not attempts.** Set it to 3 and a failing step runs four times in total: the original, then three more. Budget accordingly.

The wait is a fixed interval, not an increasing backoff.

Each retry is marked in the step's execution history as **Attempt 2**, **Attempt 3**, and so on, with its own error message and timestamp. You can see whether a step succeeded first time and how far apart the tries were. See [Executions](/build/core-concepts/executions).

> This applies to **every** step, including [HTTP
> Request](/build/action-steps/http-request). A `429` or `5xx` from an API is
> not retried unless you turn **Retry on fail** on for that step. That is
> exactly the case worth turning it on for.

### Three things never retry

Even with the setting on, three failures are not repeated because repeating them cannot help:

- **An expired or revoked connection.** The account needs reconnecting; another attempt would fail identically. See [Managing Connections](/manage/apps-and-integrations/managing-connections).
- **[Stop and Error](/build/action-steps/stop-and-error).** That step fails deliberately, with the same message every time.
- **A step whose outward call may already have gone through.** If a step sent its email or created its ticket and the confirmation never came back, Glow declines to repeat the call. Trying again could send it twice. The step is marked failed and your [error path](#if-this-step-fails-stop-or-continue) still runs, so you can decide what to do about it.

### Retries do not read the reason a step failed

Those three are the only exemptions. Every other failure is retried on the same
schedule, whatever caused it.

So a request the other service rejected on its merits (a `400` from a
malformed body, a `404` on a record that does not exist, a `422` from failed
validation) is re-sent byte for byte on every attempt. It fails the same way
each time.

At the default settings that is **ten retries, sixty seconds apart**: eleven
runs in all, ten minutes before the run moves on. Where a rejection is final,
set **Max retries** to 0 on that step and let your error path handle it straight
away.

> Retries are the right tool for a **transient** failure: a rate limit, a
> timeout, a service having a bad minute. They are the wrong tool for a step
> that fails on its own input. If a step reliably fails the same way, fix the
> input or send it down an [error path](#if-this-step-fails-stop-or-continue)
> rather than turning retries up.

Inside [Run for each item](/build/action-steps/loops) this is handled for you. A
failed item is retried only when the failure looks transient. A rejection moves
straight to failed without consuming the retry budget.

## If This Step Fails: Stop or Continue

Alongside **Retry on fail**, the same tab has an **If this step fails** setting that decides what happens once a step has given up.

- **Stop Workflow** (default): _immediately stop execution and mark the workflow as failed_.
- **Continue**: _continue running and pass the error message through the output_, so you can handle the failure yourself.

Choosing **Continue** reveals a **Select Error Path** button just below the setting. Pick the step a failure should route to, and Glow draws that path on the canvas as its own line. The normal output carries on as before, and the error path runs only when the step fails.

Note what happens if you skip that second half. With **Continue** set and no error path chosen, a failed step simply carries on to the next step in sequence, passing its error message along as its output. That is a real choice for a step whose failure does not matter, but it is rarely what someone means by "continue".

That is the usual shape of a resilient workflow: the success path does the work, the error path tells somebody or parks the data for review.

The two settings work as one machine. Retries happen first; **If this step fails** only decides what happens when they run out:

```mermaid
flowchart TD
    Run[Step Runs] --> Check{Outcome?}
    Check -->|Pass| Next[Next Step]
    Check -->|Fail| Retries{Retries Left?}
    Retries -->|Yes| Wait[Wait & Retry] --> Run
    Retries -->|No| Policy{Failure Policy}
    Policy -->|Stop Workflow| Failed[Execution Marked Failed]
    Policy -->|Continue| ErrorPath[Error Path / Next Step]
```

## Building fallback logic

When a step permanently fails, you decide how the workflow responds.

  
    **Fallback Branches** When using a [Switch](/build/action-steps/switch) step
    to route data, always configure a **Fallback** branch. If the incoming data
    doesn't match any of your expected cases, the workflow routes to the
    Fallback branch instead of crashing. This branch can send an alert to Slack
    or queue the data for manual review.
  
  
    **Manual Error Triggers** Sometimes you need to intentionally fail a
    workflow (e.g., if a customer's email is missing). Use the [Stop and
    Error](/build/action-steps/stop-and-error) step to halt execution and throw
    a custom error message. This marks the run as `Failed` in
    [Activity](/manage/workspace-settings/activity), so a handled error is not
    recorded as a success. To be told about it, put a notification on the error
    path first: see [Knowing When Something
    Failed](#knowing-when-something-failed).
  

## Knowing when something failed

Every failed run is recorded in [Activity](/manage/workspace-settings/activity) with its Step timeline and error summary. Open the workflow on the canvas, then use [Step-Level Executions](/build/core-concepts/executions) for the failing Step's output and attempt details.

To be told the moment something fails rather than going to look, build the
notification into the workflow itself. That is what the error path is for:

### Set the step to continue on error

Switch **If this step fails** to **Continue** on the step that matters, so a failure routes
down the error path instead of ending the run.

### Send yourself the alert

Put a Slack, email, or [HTTP Request](/build/action-steps/http-request) step on that path. Format the alert clearly using [Data Transformation](/build/core-concepts/data-transformation):

```markdown
🚨 _Step Failure Detected_
• _Time:_ {{ $now | format_date:"YYYY-MM-DD HH:mm:ss" }}
• _Workflow ID:_ {{ $workflow.id }}
• _Execution ID:_ {{ $execution.id }}
• _Failing Step:_ Step {{ $error.stepNumber }} ({{ $error.stepName }})
• _Error Message:_ `{{ $error.message | truncate:300 }}`
```

### Stop deliberately

End the error path with [Stop and Error](/build/action-steps/stop-and-error) so the run is still recorded as failed. Without it, a handled error reads as a success.

A notification you build says exactly what you need to know, and arrives in the channel your team already watches. Worth doing for anything you cannot afford to have fail unnoticed.

## Diagnose a failure before changing the policy

This page owns the behavior you configure for future failures. For an incident that already happened, start in [Activity](/manage/workspace-settings/activity), inspect the affected Step in [Step-Level Executions](/build/core-concepts/executions), and use [Troubleshooting & Common Errors](/reference/troubleshooting) for the symptom or exact message.

## What's Next?

- 👉 **[Activity →](/manage/workspace-settings/activity)**: find the failed run and identify the affected Step.
- **[Step-Level Executions](/build/core-concepts/executions)**: inspect each attempt and the Step's recorded output.
- **[Troubleshooting & Common Errors](/reference/troubleshooting)**: diagnose a symptom or exact error message.
