---
title: "Branches, Loops, Parallel Paths and Failures"
description: "Send a run one way or another, repeat steps for each item or until something is true, do several things at once, handle a failure without failing the run, wait, stop, and call another automation."
section: "Automations"
canonical: "https://banksync.io/docs/automations/automations-control-flow"
specs: ["automations"]
operationBindings: [{"capability":"automations","operation":"automations.nodes.describe"},{"capability":"automations","operation":"automations.nodes.test"}]
---

The **Decide** group holds the steps that shape the path of a run rather than its data. Four of them are **containers**: they hold other steps inside a lane on the canvas. Drag a card over a lane to move it in; a step inside a container reads `item` as the container's current item.

## Branch

**Which way does it go?** A branch has arms, each with a condition (**when**), and a fallback. By default the first arm whose condition is true runs; with **match all**, every true arm runs. If none is true, the fallback runs. The branch's output names the arms that ran and what each gave.

Build a condition as rows (**Status · is · Paid**) or as an expression (`item.amount > 1000 and item.category = "Transfer"`).

## Loop

**For each item in the list** runs the lane once per item. **While** runs it while a condition holds, and **until** or **stop when** end it early — the way to page through results or retry until done. A while or until loop has a **maximum number of iterations** so it cannot run away. What each iteration gives (its **yield**) is what the loop hands on.

> **Warning:** Do not put a Wait inside a loop that may run more than a few hundred times. Schedule a sweep
> instead, and keep where you got to with Save a value.

## Parallel

**Do these at the same time.** Each arm is a lane of its own. The step joins when **all of them**, **any one** or **at least *n*** have finished; what happens to arms still going when the join is decided is the step's own setting. Steps in one arm cannot read steps in another, so put what both need before the parallel step.

## Try

**Try this, and catch a failure.** The lane runs; if a step in it fails, the first **catch** lane whose error types match handles it (with `error` holding the failure), and **finally** runs either way. Use it for a failure you expect — a page that is sometimes missing, a destination that is sometimes busy — without failing the run. A **Stop with an error** inside a try is caught like any other failure.

## When a step fails

Every step has an **If it fails** tab with its own policy:

- **Retry.** How many **attempts**, the **backoff** between them (none, constant, linear or exponential, with the **first delay** and the **longest delay**) and **jitter** (none or full), optionally only for some **error types**.
- **When it still fails:** **Fail** the run, **Continue** with nothing from this step, or **Route** the failure to the step's error port so a later step can deal with it.
- **Deadlines.** A **timeout** for the step (or the whole scope, on a container), and a **heartbeat** a long step must keep up.

A retry never repeats something that already happened: a step that writes records what it wrote, and a retry sends only what is missing.

## Wait

Pauses the run **for a duration**, **until a time**, or **for an event** with a timeout — a reply on a conversation, a message reaching a mailbox. A waiting run is marked **waiting** in the runs panel and holds nothing in memory while it waits.

## Approval

**Ask someone to approve.** The run pauses until the number of people you ask have approved, or one rejects, or the time you set runs out (which counts as rejected). The decision is bound to exactly the items the step is holding, so what was approved is what goes on. Put it before anything that cannot be undone. See [Approvals and grants](/docs/automations/automations-approvals-and-grants).

## Stop with an error

Ends the scope with a failure you name (**What went wrong?**, shown in the run's history, and a **failure name** a Try can tell apart). Use it to refuse input that should never go on. Outside a Try it fails the run.

## Calling another automation

**Run another automation** starts one with the input you give it and, with **Wait for it to finish?**, waits for its answer. You choose **the version that is on** or an exact version. If this run stops first, the called run is **stopped too** or **left to carry on**, as you choose.

The called automation must list this one among the automations that may call it, and runs under its own grant. A chain of calls stops at three deep; an automation never calls itself. A failed run can start an **error automation** the same way, handed the run and its error.

## Respond to the webhook

For an automation started **On a webhook**, this step answers the request with a status code, a kind of answer (JSON or plain text) and a body. See [Webhooks](/docs/automations/automations-webhooks).

## Stopping a run from outside

The automation's settings can also end a run on your behalf: a time limit after which the run fails, is cancelled or is flagged, and events that cancel it when they arrive. A run that is cancelled, or fails, undoes what it can: a step that can be undone is undone, newest first, and the run ends **compensated**.
