> ## Documentation Index
> Fetch the complete documentation index at: https://yukta.infenia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Loop and retry

> Pick between an engine retry for a failed message and LOOP_PREDICATE or LOOP_STREAM for repeating work until a condition holds, with the bounds that keep a loop finite.

<dl />

**Use this when** something has to happen again. Two different tools cover two different needs:

| Need | Use | Scope |
| - | - | - |
| A step failed; try the same message again | `engine.retry` | One message, one node, with backoff |
| Repeat an action until a condition becomes true (polling, waiting for readiness) | `LOOP_PREDICATE` | A target plugin, repeated and bounded |
| Repeat an action and pass every result downstream | `LOOP_STREAM` | A target plugin, each result emitted as a message |

![Two tools for two needs. engine.retry runs one failed message through the same node again and, when every attempt fails, sends it out of the error port. LOOP\_PREDICATE runs a target again and again until its exit condition is true or a bound stops it.](https://yukta.infenia.com/images/diagrams/guide-loop-and-retry.light.svg)

A retry reacts to a failure; a loop reacts to a condition. Both end in a bound.

## Steps

**1. Retry a failed message**

A retry runs the failed attempt again with exponential backoff and jitter. It is for transient faults, not for waiting. Add it in the node's `engine` object and send what still fails to an `error` edge:

```json theme={"system"}
{ "nodeId": "call-api", "type": "HTTP_REQUEST",
  "config": {
    "url": "https://service.example.com/orders", "method": "POST",
    "engine": { "retry": { "maxAttempts": 4, "backoffMs": 200, "maxBackoffMs": 5000 },
                "onError": "ROUTE" } } }
```

```json theme={"system"}
{ "source": "call-api", "target": "dead-letter", "sourcePort": "error" }
```

Bad input (`IllegalArgumentException`) is not retried unless listed in `retryOn`. A retry can show the same message twice, so make side effects idempotent on the message id. All keys are in [Node options](https://yukta.infenia.com/reference/node-options.md#retry).

**2. Poll until a condition holds**

`LOOP_PREDICATE` wraps another processor, runs it again and again, and stops when `exitCondition` is true or a bound is reached. It emits only the final message. This polls a status endpoint every five seconds until the body says `done`:

```json theme={"system"}
{ "nodeId": "poll", "type": "LOOP_PREDICATE",
  "config": {
    "targetPluginId": "HTTP_REQUEST",
    "targetConfig": { "url": "https://example.com/status" },
    "exitCondition": "payload.body.state == 'done'",
    "maxIterations": 20,
    "maxDuration": "PT2M",
    "delayInterval": "PT5S",
    "failureStrategy": "ABORT" } }
```

`exitCondition` can read `#iterationCount` and `#elapsedTimeMs`. `maxIterations` defaults to 10 and `maxDuration` to `PT1M`; set both on purpose. `failureStrategy` says what a failing iteration does: `ABORT` (default), `RETRY`, `SKIP` or `ESCALATE`.

**3. Emit every result instead**

`LOOP_STREAM` takes the same options but flattens every message the iterations produce into one stream, so downstream nodes work on results as they arrive. Use it to page through results or generate a series.

**4. Mind the time limits**

A loop is one node, so the node's idle timeout and `deadlineMs` bound it. Raise `timeoutSeconds` for long polling. See [Time limits](https://yukta.infenia.com/concepts/time-limits.md).

## Verify it worked

Start a run and read it: a retried node shows its attempts in the run log, and a message that used up its attempts arrives on the `error` edge with `failure.attempts` and `failure.message` (see [Messages](https://yukta.infenia.com/reference/messages.md)). For the loop, the run ends once `exitCondition` is true, or at `maxIterations` or `maxDuration`, whichever comes first.

## Variations

* **A loop around several nodes.** A graph has no cycles. Put one round of work into its own workflow and call it with `SUB_WORKFLOW`: [Run a sub-workflow](https://yukta.infenia.com/guides/build/run-a-sub-workflow.md).
* **Do not retry AI calls blindly.** A model may return the same wrong answer, and each retry costs tokens; see the advice in the [failure model](https://yukta.infenia.com/concepts/failure-model.md).

## Related

* [Handle failures](https://yukta.infenia.com/guides/build/handle-failures.md) for routes, budgets and join rules.
* [Routing and flow reference](https://yukta.infenia.com/reference/plugins/routing-and-flow.md) for every loop option.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.