Sunday, June 29, 2025

Mastering Custom Retry and Delay Logic in n8n

One of the most common challenges when building a workflow is dealing with external APIs. Services often have rate limits, temporary outages, or other issues that can cause your workflow to fail. While n8n offers a built-in retry mechanism on most nodes, its options are limited. This guide will walk you through how to build a robust, custom retry and delay system that gives you complete control over your workflow's behavior.

The Limitations of n8n's Default Retry Settings

Most nodes in n8n have a "Settings" tab where you can configure basic retry behavior. You can specify a maximum number of tries and a fixed delay between them.

The default retry settings in an n8n node's "Settings" tab, showing options for "Maximum Tries" and "Delay Between Tries."

However, the maximum delay is capped at 5,000 milliseconds (5 seconds), and the maximum number of tries is limited to 5. This simply isn't enough for many real-world scenarios. For example, if an API has a strict 60-second throttling period, a 5-second delay won't help you at all. To handle these situations, you need to build your own logic.

Building a Custom Retry Loop: Step-by-Step

Our custom solution will use a few core n8n nodes to create a flexible loop that retries a failed node with a custom delay and for a custom number of times. Let's build it together.

Step 1: Initialize Your Retry Variables with a Set Node

First, we need to define the rules for our retries. We'll use a Set node to create and store these variables at the beginning of the workflow.

  • Node Name: Set Fields
  • Key: max_tries
  • Value: A number representing the total number of attempts you want to make (e.g., 6).
  • Key: delay_seconds
  • Value: A number representing the initial delay in seconds (e.g., 30 for a 30-second delay).

This initial Set node acts as the control panel for our retry logic, making it easy to change the settings later without modifying the rest of the workflow.

The Set Fields node configured with two keys: max_tries and delay_seconds with their respective initial values.

Step 2: Configure Your Target Node to Handle Errors

Next, add the node that might fail—in this example, an HTTP Request node. This could be any node that calls an external service. The critical part here is to tell the node what to do when it encounters an error.

An HTTP Request node, which is the target node for the custom retry logic.

  • In the Settings tab of your HTTP Request node, find the On Error dropdown.
  • Change the setting to Continue (using error output).

The "Settings" tab of an HTTP Request node with the "On Error" dropdown set to Continue (using error output).

This setting is essential. Instead of stopping the workflow, it will send the failed data to a new output branch, allowing us to process the error and decide whether to retry.

Step 3: Decrement the Retry Counter

When the target node fails, the data will flow to its "Error" output. We will use the max_tries variable as our counter and decrement it with each failed attempt. We also need to keep the delay_seconds variable in our data to be used later in the loop.

  • Connect another Set node to the Error output of your target node.
  • Node Name: Edit Fields
  • Key: delay_seconds
  • Value: {{$json.delay_seconds}}. This ensures the delay value is carried through the loop without being changed.
  • Key: max_tries
  • Value: Set this value using the expression: {{$json.max_tries - 1}}. This expression simply subtracts 1 from the current value of max_tries with each iteration, tracking our remaining attempts.
The Edit Fields node showing the expression {{$json.max_tries - 1}} for the max_tries key and the expression {{$json.delay_seconds}} for the delay_seconds key.

Step 4: Check if Tries are Remaining with an If Node

Now that we've decremented the counter, we need to check if we should continue trying.

  • Connect an If node to the Edit Fields node.
  • Condition: left value should be {{$json.max_tries}}, Operation should be Is Less Than or Equal, and right value should be 0.

The If node configured to check the condition where the max_tries value is less than or equal to 0.

This If node will have two outputs:

  • True: This path is followed if max_tries is 0 or less. This means we are out of tries, and the workflow should handle the final failure.
  • False: This path is followed if max_tries is greater than 0. This means we still have attempts left.

Step 5: The Delay and Loop Back

This is where the magic happens! We'll use a Wait node to pause the workflow before trying again.

  • Connect a Wait node to the False output of the If node (the path where we still have attempts remaining).
  • Wait Amount: Set this to {{$json.delay_seconds}}. This is the dynamic value we defined in our first Set node.
  • Wait Unit: Seconds

Finally, connect the output of this Wait node back to the input of your target HTTP Request node. This creates a loop. When a failure occurs and we have retries left, the workflow waits for the specified delay and then re-executes the target node.

A screenshot of the complete n8n workflow, including the loop connecting the Wait node back to the target HTTP Request node.

The Wait node with "Wait Amount" set to {{$json.delay_seconds}} and "Wait Unit" set to "Seconds."

Advanced Logic: Exponential Backoff

The basic loop uses a fixed delay, but you can make it even smarter. A powerful technique called exponential backoff can prevent you from overloading a server by increasing the delay with each failed attempt.

To implement this, simply modify your Edit Fields node in Step 3. The delay_seconds key's value would be updated like this:

  • Key: delay_seconds
  • Value: {{$json.delay_seconds * 2}}

Now, each time the loop runs, the delay will double. This makes your workflow more polite to the external API and gives the service more time to recover.

What Happens on Success and Final Failure?

  • Success: When the target node finally succeeds, it will no longer send data to the "Error" output. Instead, the data will continue down the "Success" output branch, and the retry loop will be bypassed entirely.
  • Final Failure: If all tries are exhausted, the If node will send the data down its True output (where max_tries is not greater than 0). You can connect a Stop And Error node here to halt the workflow or use a notification node to send an email or a Slack message, alerting you that the task ultimately failed.

By building this custom loop, you gain the flexibility to handle a wide range of API and service issues, making your workflows more resilient and reliable.

Let's execute the workflow to check this approach.

A screenshot of the n8n workflow's execution history, displaying that the target node was run multiple times as defined by the custom retry logic.

You'll see that the target node is called exactly the number of times specified in the initial Set node, confirming the reliability and control of this custom retry mechanism.

An n8n template for this approach can be found here.

No comments:

Post a Comment