Module 2: Robust Error Handling

3. Automatic retries: Retry On Fail

Description

By the end of this lesson you'll be able to enable and configure a node's automatic retry in n8n 2.x —the Retry On Fail checkbox in the Settings tab, with its Max Tries and Wait Between Tries (ms) fields—, you'll know how to choose the values with judgment for each of Terra Market's three workflows, and you'll recognize in the panel what an execution where there were retries looks like. You'll also learn a concrete prior-verification procedure, because enabling this checkbox isn't always an improvement: on some nodes it turns a recovery tool into a duplicate machine.

This matters because the retry is, by far, the layer that resolves the most failures for the least work. It's a checkbox. It requires no code, no extra nodes, no infrastructure. And in a system like Terra Market's —four thousand daily executions against three third-party APIs— it sweeps away the vast majority of the transient failures you learned to recognize in lesson 2, without any human being having to find out about anything. But it's also the layer that does the most harm when badly applied, and for an unintuitive reason: when you retry, you don't know whether the previous try managed to have an effect before failing.

Connection to the module: lesson 2 taught you to classify a failure; this one enables the layer that resolves exactly one of those four types —the transient one— and helps partially with another —the external system one, if the outage is short. It's layer 1, the innermost of the schema from lesson 1: what the system resolves on its own, without anyone finding out. What the retry can't heal passes to layer 2, which is lesson 4. An important border right away: the theory of why repeating an effect can duplicate it —idempotency keys, upserts, conditional writes— lives in the n8n-workflow-contracts-and-idempotency-guide guide. Here we treat it as a safety condition you verify before enabling the checkbox, with a concrete procedure to verify it.

The turnstile that charged you and didn't open

You're going into the subway. You tap your card on the reader, and nothing happens: the gate doesn't open. You tap it again and this time it does open. You go on your way.

That's the whole scene of the retry: something didn't work, you try again, it works. Cheap, instant, invisible. Most of the times you tap the card twice it's because you tapped it wrong or the reader didn't read it, and repeating is exactly the right solution.

Now think about the other possibility, the uncomfortable one. The first time the reader did read your card and did charge you the fare, but the gate jammed and didn't open. You can't know it: from where you are, "it didn't open" looks identical in both cases. You tap the card again, the gate opens, and you've just paid two fares for a single ride.

And this is the part I want you to take away: the retry can't tell those two worlds apart, and it never will. It's not a limitation of n8n. It's a property of the problem. When a request fails, there are two possible stories behind it —"it never arrived" and "it arrived, it ran, and what was lost was the response"— and from your side they look exactly the same: a timeout.

That's why the safety of a retry doesn't depend on the retry, which always does the same thing. It depends on how bad it is for the effect to happen twice. If the turnstile were designed so that two reads of the same card in the same minute count as one, tapping the card five times would be harmless. That design —that repeating doesn't duplicate— is what the contracts and idempotency guide teaches you to build. What you do here, as an operator, is find out whether it exists before switching on the checkbox.

Anatomy of Retry On Fail

Let's get to the mechanics. All of this lives in any node's Settings tab: you open the node, and next to the tab for its own parameters there's one for settings.

The official documentation describes the option like this: when an execution fails, the node is re-run until it succeeds. Enabling it reveals two fields:

Node → Settings tab
  ├─ Retry On Fail:            [✓]
  │    ├─ Max Tries:                 [ 3 ]       ← how many tries
  │    └─ Wait Between Tries (ms):   [ 2000 ]    ← wait between one and the next
  │
  └─ On Error:                 [ Stop Workflow ▾ ]  ← what happens if it fails at the end

Max Tries. The documentation describes it as the maximum number of times n8n should retry the node. It's the retry's brake: without it, a node could keep trying against a downed API indefinitely.

Verify this in your panel, and verify it by running. There are two things the documentation doesn't fix with numbers and that you'd do well to check yourself: (1) whether Max Tries counts the original try or only the retries —that is, whether 3 means three tries total or one plus three—, and (2) what the maximum value the field accepts is in your version, which has changed between versions. The way to check is direct: put an HTTP Request node pointing at a URL you know always fails, set Max Tries to 3 and Wait Between Tries (ms) to 5000, run it, and time how long it takes to give up. If it takes about 10 seconds, it was three tries (two waits). If it takes about 15, it was four (three waits). Thirty seconds of testing give you a fact you'll use for years.

Wait Between Tries (ms). How long the node waits between one try and the next, in milliseconds. Remember that a thousand milliseconds is a second, so 2000 is two seconds. The documentation gives a very concrete and very useful example: if the API you call allows one request per second, set 1000 to respect that limit.

This field looks like a detail and it isn't. Think about it from the other side: if a service is saturated, sending it three requests in a row with no pause is adding load right when it's weak. The wait exists to give the other side a moment to breathe before touching it again. And when the failure is a 429 Too Many Requests —"you're going too fast"—, the wait is the solution: retrying at 200 milliseconds gives you back another 429, and retrying at 30 seconds works.

An idea worth knowing even though n8n doesn't bring it out of the box: backoff, which consists of waiting longer and longer between tries —one second, then two, then four— on the logic that if the service didn't recover in one second, maybe it needs more. The n8n field applies a fixed wait, the same between each pair of tries, and for the vast majority of business automations that's more than enough. If someday you truly need growing backoff, it's built by hand with a loop and a wait node, but it's a rare case. For now keep the intuition: some wait almost always recovers more failures than none.

On Error. It's not part of the retry, but it decides what happens after the retries run out. Its three options are Stop Workflow, Continue, and Continue (using error output), and they're the whole topic of lesson 4. For now keep the relationship between the two configurations in mind, which is one of sequence:

The node fails
    │
    ├─ Retry On Fail enabled?  ── yes ──► tries again, up to Max Tries
    │                                          │
    │                                          ├─ works ──► the workflow continues normally
    │                                          │            (nobody finds out)
    │                                          └─ runs out ──┐
    │                                                         │
    └─ no ─────────────────────────────────────────────────────┤
                                                              ▼
                                                    now On Error applies

The retry goes first. On Error only comes into play when the retry has already given up, or when there was no retry configured.

Worked example: retries in shipment-notify

We're going to put retries in the clearest case of Terra Market's system. If you have an instance handy, follow along; if not, read it and do it later.

The context. shipment-notify is the highest-volume workflow: 2,500 daily executions. When andes-express reports a status change, this workflow queries the shipment detail and sends an email to the customer. It looks like this:

Webhook: carrier event ──► HTTP Request: Get tracking status ──► Send email to customer
                                    ▲
                          the carrier API returns 503
                          one in every hundred calls

The Get tracking status node does a GET to the carrier's API. It's the one that times out every so often, exactly failure 1 of the triage in lesson 2.

Step 1 — The prior verification. Before touching anything, the question that decides everything: if this request is sent twice, what happens on the other side?

Here the answer is easy and it's the best of all: it's a GET, a read. Querying the status of a shipment changes nothing in the carrier's system. You can query it a hundred times and the result is the same. Repeating is harmless by nature, so the retry is safe with no conditions.

Keep this observation, because it's the most useful in the lesson: reads get retried without fear. When you're in doubt about a node, start by asking whether it reads or writes.

Step 2 — Enable the checkbox. Open the Get tracking status node, go to the Settings tab, and enable Retry On Fail. The two fields appear.

Step 3 — Choose the values. Set Max Tries to 3 and Wait Between Tries (ms) to 2000.

The why of those numbers, which is what matters:

  • 3 tries because genuinely transient failures almost always heal on the second or third. A failure that needs eight tries isn't a stumble: it's a service that's systematically broken, and hiding it with more tries is exactly the opposite of what you want.
  • 2000 milliseconds because it gives the carrier API two seconds to recover, and because the total cost is acceptable: in the worst case, this node takes about four seconds longer than normal before giving up. For a notification email, four seconds matter to nobody.

Step 4 — Leave a record. In the same Settings tab, write in Notes something like:

Retry enabled (3 × 2000 ms): the andes-express API returns sporadic
503s. Safe because it's a read-only GET.

And enable Display note in flow so it shows on the canvas. This does nothing technically and it's one of the most valuable things you'll do: six months from now, you or someone else will open this workflow at three in the morning and that note answers immediately the question "why does it have retries and is it safe?".

What to expect. Save and let it run. What you'll observe in the panel from now on is an interesting change, because the retry is a silent layer:

  • Most executions look exactly the same as before: green, fast. They're the ones that hit no problem.
  • Some —about one in every hundred— stay green but with a notably longer execution time: two or four seconds more. Those are the ones that stumbled and recovered. The duration spike is the only visible trace.
  • The red executions from this node's 503 almost disappear. The ones that remain are the cases where the API was down for more than four seconds in a row, which is no longer a transient failure but an external-system one.

That last point is the result you're after, and it has a second-order effect that's the real prize: red means something again. When shipment-notify had twenty daily "normal" reds, nobody looked at them. When it has zero or one, a red is a signal someone attends to.

A panel-reading detail. The growing execution time is your main clue that there were retries, but it isn't conclusive proof: an execution can also take longer because the API responded slowly without failing. If you need to know for certain how many times a specific node retried, that fine traceability belongs to Module 4 (observability) and Module 3 (reading an execution in depth). As an operator, for now keep the coarse signal: durations that spike every so often in a workflow with retries are retries doing their job.

The prior verification: reads or writes

This is the part of the lesson I want to stick with you, because it's what separates enabling a checkbox from operating with judgment.

Before enabling Retry On Fail on any node, you answer one question: if this operation runs twice, what happens?

There are three possible answers and each leads to a different decision.

Answer A — "Nothing happens, it's a read". The node queries, searches, fetches. A GET to an API, a SELECT in Postgres, reading a row from a spreadsheet. Repeating a read is harmless by definition: the world doesn't change because you ask twice.

Decision: enable the retry with no further formality. This is the majority case and the ideal case.

Answer B — "The effect duplicates". The node creates, sends, charges, writes. A POST that creates an order, a node that sends an email, a write that inserts a new row. If the original try managed to run and only the response was lost, retrying does the thing twice.

Decision: don't enable the retry yet. First the design problem has to be resolved: that repeating doesn't duplicate. That's the whole topic of the contracts and idempotency guide —idempotency keys, upserts, the Idempotency-Key header. When that protection exists, the retry becomes safe and you enable it with peace of mind.

Answer C — "I don't know". And it's an honest and frequent answer, especially with poorly documented third-party APIs.

Decision: find out before enabling. And there's an operational way to find out that doesn't depend on the documentation:

  1. Look at the method. A GET is almost always a read. A POST almost always creates. A PUT normally replaces a whole resource with an identifier you provide, which is usually repeatable without harm. A DELETE is usually repeatable too —deleting something already deleted does no second harm— though it may return an error the second time. It's a heuristic, not a guarantee.
  2. Search the API documentation for the words idempotency or Idempotency-Key. If the API offers that mechanism, it's explicitly telling you it knows how to recognize repeated requests.
  3. Test it in a test environment. Send the same request twice by hand and see what remains on the other side: one record or two? This is the only conclusive proof.
  4. If you can't test and it isn't documented, assume the worst. In operation, the asymmetry of risks rules: not retrying costs a failure that someone recovers by hand; retrying badly costs a duplicate that maybe nobody notices until it's a billing problem.

Applied to Terra Market, the result is this table, which is the system's retry policy:

NodeWhat it doesDoes repeating harm?Retry
Get tracking status (shipment-notify)GET to the carrierNo: it's a readYes, no condition
Fetch stock from ERP (inventory-update)GET to the ERPNo: it's a readYes, no condition
Create order in ERP (order-sync)POST that creates an orderYes: two ordersOnly if the erp recognizes the idempotency key
Send email to customer (shipment-notify)Sends an emailYes: two emails to the customerOnly with protection; and see the note below
Push stock to storefront (inventory-update)Writes the stock of a skuNo, if it writes the absolute valueYes, with an important nuance

Stop on the last two rows, because they teach something fine.

The email. Duplicating it doesn't cost money, but it costs image and generates support tickets. At Terra Market we decided to enable a retry for it with Max Tries set to 2 —the useful minimum— because the risk of a customer not receiving their notification is greater than that of receiving two. It's a business decision, not a technical one, and in another company it could be the reverse. What matters is that it be a decision and not an oversight.

The stock write. Here's the most interesting nuance in the whole table. If the node writes "the stock of sku CAF-VER-250 is 42", repeating it is harmless: the final result is the same, 42, no matter how many times you write it. But if the node wrote "subtract 3 from the stock of CAF-VER-250", repeating it would subtract 6. Same table, same field, same node, and the safety of the retry depends entirely on how the operation is phrased. Writing an absolute value is repeatable; applying an increment is not.

That distinction is the heart of idempotency, and its full development —how to turn an increment into an absolute value, how to design an upsert, what to do when the effect can't be rephrased— is in the contracts and idempotency guide. Here it's enough to recognize it to make the right operational decision.

Choosing the values: there's no universal number

3 and 2000 work surprisingly well as a starting point, but it's worth understanding what moves those numbers so you can adjust them.

How much time you add. The worst cost of a retry is approximately (Max Tries - 1) × Wait Between Tries, plus the time of the tries themselves. With 3 × 2000, you add about four seconds before giving up. With 5 × 10000, you add forty. That time matters depending on the context:

  • In a workflow triggered by a webhook that responds to the caller, forty seconds can exceed the time the other system is willing to wait, and then the caller times out even if you succeeded in the end.
  • In a workflow with high volume, each execution that stays waiting occupies an execution slot. In a system with limited concurrency, long retries in a workflow with 2,500 daily executions can cause work to pile up. Module 6, on scaling and queue mode, deals with this effect in detail.
  • In a scheduled workflow that self-corrects, like inventory-update, the time barely matters. You can afford long waits.

The API's rate limit. If the other side allows you N requests per minute, your wait between tries should respect it. The n8n documentation says so with a direct example: one request per second, Wait Between Tries (ms) set to 1000.

The nature of the failure you expect. A network timeout heals in milliseconds; a 503 from saturation can take seconds; a 429 explicitly tells you how long to wait. If you know the typical failure of that API, adjust to it.

With that, Terra Market's policy ends up like this:

WorkflowNodeMax TriesWait (ms)Why
shipment-notifyGet tracking status32000Read, high volume, customer waiting for their notification
shipment-notifySend email to customer23000Visible write: useful minimum, duplicate risk accepted
order-syncCreate order in ERP32000Only after confirming the erp accepts an idempotency key
inventory-updateFetch stock from ERP45000Read, no rush: the run is every 15 minutes
inventory-updatePush stock to storefront33000Writes an absolute value, not an increment: repeatable

Notice inventory-update: it's the one with the most tries and the most wait, precisely because it's the one in least of a rush. Nobody is waiting for that run. It can afford to insist calmly. And shipment-notify, which is the highest-volume one and has a customer waiting, is the one that insists least.

That's the right way to think about the values: not "which is the good number," but how much this workflow can wait and how much each second it waits costs.

Retrying the node vs retrying the execution

There are two different things called "retry" in n8n and it's worth not confusing them, because one is automatic and the other you do.

The node retry is the one in this lesson: it happens inside an execution, automatically, while the workflow runs. If it works, the execution continues as if nothing happened and finishes green. It's the front-line reaction, and its virtue is that nobody has to do anything.

The whole-execution retry is different: an execution has already finished marked as failed, and you, from the executions list, decide to relaunch it in full. It's a manual recovery tool, with a cool head, after the fact. Normally n8n offers you two variants —retry with the workflow as it was when it failed, or with the current saved version, which is what you want if you already fixed the problem—, and you'd do well to confirm the exact labels in your version, because the executions interface changed quite a bit in n8n 2.x.

The practical difference: the node retry is for transient failures that heal in seconds. The execution retry is for when the failure has already been recorded and you decide to reprocess it, almost always after fixing the cause.

And watch out for the same thing as always, because here it bites harder: retrying a whole execution re-runs all its nodes, including the ones that did work the first time. If the execution managed to create the order in the erp and failed at the next node, retrying it in full tries to create the order again. The same rule governs both levels, and Module 3 —debugging with the replay engine— develops the safe procedure for doing it.

When to leave it off

As important as knowing how to enable the retry is knowing when not to. These are the four situations where Retry On Fail off is the right decision.

When the failure isn't transient. You already worked on this in lesson 2: a 401, a 403, a 400, or a TypeError from your own code will give the same result on the tenth try. Retries are for stumbles of the moment, not for data or configuration problems. Retrying them only adds latency and fills the history with identical tries.

When the effect can't be repeated without harm and you have no protection. You already saw it: first the design is resolved, then the checkbox is switched on. Never the other way around.

When the "failure" is really a business response. If the erp API responds "that sku doesn't exist," that isn't a failure: it's a no. Retrying it ten times gives ten nos. These cases shouldn't even arrive as a node error; the right thing is for them to be a normal output that an If or Switch node routes toward the "couldn't be fulfilled" path.

When many tries would hide a real problem. If you set Max Tries very high, a service that's systematically degraded will keep working —slowly and at the cost of insisting— and nobody will find out there's something to fix. The retry is a safety net, not a rug to sweep things under. Two or three tries catch almost all genuine stumbles; beyond that, you're probably covering up something that deserved an alert.

Common mistakes

Enabling the retry on a node that creates something, without verifying whether repeating duplicates (conceptual). What happens: Retry On Fail is enabled on the Create order in ERP node "to make it more robust." Everything works in testing, because in testing the API responds on the first try. In production, one day the API responds slowly —it creates the order but the confirmation is lost—, n8n retries, and a duplicate order appears in the warehouse. Someone packs and ships twice. Why it happens: the retry feels like a harmless improvement, and the "the effect happened but the response was lost" scenario practically never appears in development, so it isn't seen coming. How to detect it: review every node in your system with Retry On Fail enabled and ask yourself the prior-verification question: "does this node read or write?". If it writes and you can't find what protects it from a repeated request, you have a duplicate waiting for its day. How to fix it: turn off the retry on that node until you resolve the design. The concrete protection —idempotency key, upsert, writing an absolute value instead of an increment— is what the contracts and idempotency guide teaches; until it exists, Retry On Fail off is the safe option.

Setting Wait Between Tries (ms) to zero or very low (practical). What happens: the retry is enabled with a wait of 0 or 100 so it'll "be fast." When the API is saturated, the three tries go out almost simultaneously, hit the same saturated service, and all three fail in a fraction of a second, giving it no chance to recover. The retry recovered nothing and on top of that added load to the service at its worst moment. Why it happens: waiting feels like wasting time, and on the happy path it is —but the retry doesn't exist for the happy path. How to detect it: if your executions with retry fail almost the same millisecond as the original try, there was no room for anything to heal. How to fix it: set at least 1000, and align the value with the API's rate limit when you know it. In the specific case of a 429, the wait has to be longer than the limit window or the retry is pure noise.

Raising Max Tries when something fails repeatedly (practical). What happens: inventory-update starts failing more than it should, someone raises Max Tries from 3 to 10, and the failures "disappear." For three weeks everything looks fine. Then, the erp gets a bit worse, the ten tries stop being enough, and now there's a much bigger problem that has been growing for three weeks without anyone looking at it. Why it happens: raising the number works in the short term and is the easiest action, so it feels like having fixed something. How to detect it: if at some point you raised Max Tries as a reaction to an increase in failures, instead of investigating why they increased, you're in this case. How to fix it: treat a sustained increase in retries as what it is —a signal that something on the other side is degrading— and keep it visible instead of absorbing it. A high Max Tries value doesn't fix a bad service; it just covers your eyes while it gets worse.

Exercises

Exercise 1 — The prior verification. For each of these six Terra Market nodes, say whether you'd enable Retry On Fail, and if your answer is "yes with a condition," what that condition is:

(a) GET /v2/orders/{order_id} to the erp to query an order's status. (b) POST /v2/orders to the erp to create a new order. (c) A Code node that computes the order total by summing quantity × unit_price. (d) PUT /v1/inventory/{sku} that writes a sku's absolute stock in storefront. (e) A node that sends an email to the customer telling them their package shipped. (f) A Postgres node that does INSERT INTO dead_letter (...) with a set-aside order.

See solution

(a) Yes, no condition. It's a pure read. Querying an order's status changes nothing. Ideal case.

(b) Yes, but with a condition: that the erp recognizes repeated requests. A POST that creates is exactly the dangerous case. If the erp accepts an idempotency key (search for Idempotency-Key in its documentation), the retry is safe. If not, don't enable it and resolve the design first.

(c) Yes, though it adds nothing. A calculation inside a Code node doesn't call anything external, so it rarely fails for transient causes; and if it fails from bad data, retrying gives the same error. It does no harm, it doesn't help. It's the case where the checkbox is indifferent.

(d) Yes, no condition, thanks to how it's phrased. Notice that it writes the absolute value of the stock, not an increment. Writing "the stock is 42" three times leaves 42. If the endpoint were POST /v1/inventory/{sku}/decrement with {"by": 3}, the answer would be completely different: three retries would subtract 9.

(e) Yes with a condition, and the condition here is a business decision. Duplicating an email breaks nothing in the system, but it annoys the customer and generates tickets. With Max Tries set to 2 you limit the possible damage to one extra email in the worst case, in exchange for recovering most of the failed sends. It's a trade-off, and what matters is that it be deliberate.

(f) Yes, with a nuance that depends on the table design. A plain INSERT would create two rows in dead_letter if retried after having written. Usually it's not serious —two identical rows in the queue are noise, not harm— but if the table has a uniqueness constraint on order_id, the second INSERT would fail with a duplicate error and the retry would never "succeed." This is a good example that the safety of the retry depends on the exact form of the operation, not on the node.

Why it works: notice that the question that resolves all six cases is always the same —"what remains on the other side if this runs twice?"— and that the answer rarely depends on the node: it depends on the verb of the operation. Reading, writing an absolute value, and creating are three verbs with three completely different risk levels, and recognizing them is 90% of the judgment.

Exercise 2 — Compute the cost. The order-sync workflow responds to a storefront webhook, and storefront cuts the connection if n8n doesn't respond within 20 seconds. The workflow has three nodes that call external APIs, and you want to put retries on all three. If you set each one to Max Tries: 4 and Wait Between Tries (ms): 5000, what can go wrong? Compute the worst case.

See solution

The worst case: each node with Max Tries: 4 does three 5-second waits before giving up, that is, about 15 seconds of pure wait per node, not counting the time of the requests themselves.

With three nodes like that in series, if all three stumble in the same execution, you accumulate 45 seconds of waits alone. And since storefront cuts off at 20, the following happens: the caller times out while n8n keeps working.

The consequences, which are worse than they seem:

  • storefront believes the request failed. Depending on how it's programmed, it will probably retry it, firing the webhook again. Now you have two executions of the same order running in parallel.
  • The original execution may finish fine anyway, after the caller gave up. Result: the order was created, but storefront believes it wasn't.
  • And if the two executions both succeed, the order was created twice, without any n8n retry having duplicated anything. The duplicate came from the caller.

What I'd do in your place, in order of preference:

  1. Lower the values so the worst case fits comfortably within the caller's window: with 3 × 1500 per node, the worst case is about 9 seconds total, within the 20.
  2. Respond to the webhook immediately and process separately. The pattern is that the webhook node answers "received" instantly and the heavy work happens afterward, so the retries stop being inside the caller's window. It's the structural solution, and its full design belongs to the contracts and idempotency guide.
  3. Put retries only on the node that most needs them, instead of on all three out of habit.

Why it works: the exercise shows that the retry isn't free. Its cost is time, and time, in a workflow with someone waiting on the other side, turns into a different and worse problem than the one you were solving. When you configure retries, always compute the accumulated worst case of the whole workflow, not that of an isolated node.

Exercise 3 — Design the retry policy of a new workflow. Terra Market is going to launch seller-payout, a workflow that runs once a day, computes how much each seller is owed, and executes the transfers against the bank's API. Write the retry policy: which nodes get a retry, with what values, which don't, and what you'd have to verify before switching on the one that worries you most.

See solution

A defensible policy, node by node:

Fetch sales for period (GET to the erp). Retry yes, no condition: it's a read. And with generous values, Max Tries: 5, Wait Between Tries (ms): 10000, because this workflow runs once a day in the small hours and absolutely nobody is waiting. It can afford to insist calmly for almost a minute.

Calculate payouts (Code node). Retry indifferent. It calls nothing external. If it fails, it's from bad data, and retrying doesn't change the data. I'd leave it off so as not to confuse whoever reads the workflow later.

Execute bank transfer (POST to the bank's API). This is the one that matters, and the correct answer is: don't switch it on until you verify. It's the most dangerous effect to duplicate a system can have: money going out twice. What to verify first:

  1. Does the bank's API accept an idempotency key? Almost all serious payment APIs accept it; look for it in their documentation.
  2. If it does, is your request sending it, and is that key stable between retries? A key derived from the seller_id and the period is stable; one derived from the current time is not, and would ruin the whole protection.
  3. Can you test it in the bank's test environment by sending the same request twice and verifying that only one transfer is generated?

If all three answers are yes, enable the retry with conservative values —Max Tries: 3, Wait Between Tries (ms): 5000— and leave it documented in Notes. If any answer is no, leave it off and let the failure fall into the error branch for manual review: a payment left pending that someone executes by hand is infinitely better than a duplicated payment.

Notify seller by email. Retry yes, Max Tries: 2, same logic as the shipment-notify email: better one extra email than none.

Write payout record to ops. Retry yes, provided the write is an upsert by payout_id and not a blind INSERT. If it's a blind INSERT, two rows of the same payment in your internal records will make your reports lie.

Why it works: this exercise brings together everything in the lesson in the case where being wrong hurts most. Notice the general pattern of the policy: reads get generous values because they're free; writes get conservative values and a prior verification; and the node that moves money isn't switched on until there's a proof, not a supposition. That asymmetry —generous with the harmless, strict with the irreversible— is how you operate a production system.

Summary and next step

In this lesson you enabled the first layer of defense. You saw with the image of the turnstile that the retry can't tell "the request never arrived" from "the request arrived and only the response was lost," and that's why its safety doesn't depend on the retry but on how bad it is to repeat the effect. You got to know the anatomy of Retry On Fail in the Settings tab, with Max Tries —the maximum number of times n8n retries the node— and Wait Between Tries (ms) —the wait between tries, with the official example of 1000 for an API that allows one request per second—, and it was noted what you must verify yourself in your panel because the documentation doesn't fix it: whether Max Tries includes the original try and what its cap is. You configured the retry of Get tracking status in shipment-notify and saw what to expect in the panel: the trace of a successful retry is a duration spike, not a red. You learned the prior-verification procedure —read, write, or I don't know— with its four steps for the third case. And you saw that the values aren't universal: they depend on how much the workflow can wait and how much each second it waits costs.

Before moving on you should be able to: enable Retry On Fail and explain what each field does; decide whether a specific node can have a retry with the question "what remains on the other side if this runs twice?"; and compute the worst-case latency your retries add to a whole workflow.

What you haven't seen yet is what happens when the retry isn't enough. Because the three tries run out, and then the node has to decide: do I stop the whole workflow?, do I keep going as if nothing happened?, do I set this item aside and let the rest through? That decision is the On Error dropdown, with its three options —Stop Workflow, Continue, and Continue (using error output)—, and its third option opens a second connection on the node that turns error handling into something you design on the canvas instead of hiding in a checkbox. Lesson 4 is the error branch: how it's connected, what's done with the set-aside item, and why a batch of three hundred sku should never fall because of three.

Resources

  • Work with nodes — n8n Docs — the Settings tab of any node, with the official description of Retry On Fail, On Error and its three options, Always Output Data, Execute Once, and Notes.
  • Handle rate limits — n8n Docs — how to use Retry On Fail, Max Tries, and Wait Between Tries (ms) to respect rate limits, with the example of 1000 ms for a one-request-per-second API, and the HTTP Request node's Batching option.
  • HTTP Request node — Common issues — n8n Docs — the common issues of the node you'll configure the most retries on, including the definition of Max Tries as the maximum number of times n8n retries the node.
  • Handle errors gracefully — n8n Docs — the general framework of error handling where the retry is the first piece.
  • Release notes 2.x — n8n Docs — to confirm your version and check whether the caps or the field names changed since July 2026.