# How to Retry Failed Workflows in n8n

- Tool: n8n
- Difficulty: Beginner
- Time required: 10-15 minutes
- Compatibility: n8n 1.0+ (self-hosted and Cloud)
- Last updated: March 2026

## TL;DR

To retry failed workflows in n8n, open the Executions tab, find the failed execution, and click Retry. You can retry with the original data or the current workflow version. For automated retries, enable Retry On Fail in node settings or create an Error Trigger workflow that catches failures and re-runs the workflow using the Execute Workflow node.

## Retrying Failed Workflow Executions in n8n

Workflows fail for many reasons: API rate limits, network timeouts, invalid data, and third-party service outages. When a failure happens, you need a way to re-run the workflow without manually re-creating the input data. n8n provides three retry mechanisms: manual retry from the Executions tab, per-node Retry On Fail settings, and Error Trigger workflows that automatically handle failures. This tutorial covers all three approaches.

## Before you start

- A running n8n instance (v1.0 or later)
- At least one workflow that has failed executions
- Execution data saving enabled (EXECUTIONS_DATA_SAVE_ON_ERROR=all)

## Step-by-step guide

### 1. Manually retry a failed execution from the Executions tab

Open the Executions tab from the left sidebar or from within the specific workflow's editor. Filter by Error status to see only failed executions. Click on the failed execution to open its details. You will see the workflow with the error highlighted on the node that failed. At the top of the execution view, click the Retry button. n8n gives you two options: Retry with original workflow (uses the workflow version from the time of the original execution) or Retry with current workflow (uses the latest saved version). Choose the option that fits your situation.

**Expected result:** The workflow re-executes with the original input data. A new execution record is created showing the retry result.

### 2. Enable Retry On Fail for individual nodes

For nodes that interact with external APIs (like HTTP Request, OpenAI, or database nodes), you can configure automatic retries. Open the node settings by clicking the node, then go to the Settings tab. Toggle on Retry On Fail. Set the Max Tries (how many times to retry, typically 2-3), and the Wait Between Tries in milliseconds (start with 1000ms and increase for rate-limited APIs). When this node fails, n8n automatically retries it before marking the execution as failed.

**Expected result:** The node automatically retries on failure up to the configured number of times before the workflow is marked as failed.

### 3. Configure the node's On Error behavior

Each node has an On Error setting under the Settings tab with three options: Stop Workflow (default), Continue (outputs error data to the next node), and Continue (using error output). The third option creates a second output on the node — one for success, one for errors. Connect the error output to a separate branch that handles the failure, such as sending a notification or logging the error. This way, a single node failure does not stop the entire workflow.

**Expected result:** Failed items are routed to the error branch while successful items continue through the main workflow path.

### 4. Build an Error Trigger workflow for automated failure recovery

Create a separate workflow that starts with an Error Trigger node. This node fires whenever any workflow in your n8n instance fails (or you can scope it to specific workflows). The Error Trigger receives the error details including the workflow ID, execution ID, and error message. Connect it to nodes that send notifications (like email or Slack) and optionally to an Execute Workflow node that re-runs the failed workflow. This gives you a centralized error handling and retry system.

**Expected result:** When any monitored workflow fails, the Error Trigger workflow fires, sends a notification, and optionally retries the failed workflow.

### 5. Implement retry logic with backoff in a Code node

For more control over retry behavior, including exponential backoff, implement retry logic in a Code node. This approach wraps an HTTP request in a retry loop that waits progressively longer between attempts. Use this when the built-in Retry On Fail settings do not offer enough control, such as when you need exponential backoff, different retry strategies per error code, or custom logging between retries.

```
// Code node: HTTP request with exponential backoff
// Mode: Run Once for All Items

const MAX_RETRIES = 3;
const BASE_DELAY_MS = 1000;

async function fetchWithRetry(url, options, retries = 0) {
  try {
    const response = await this.helpers.httpRequest({
      method: 'POST',
      url: url,
      body: options.body,
      headers: options.headers,
      returnFullResponse: true
    });
    return response;
  } catch (error) {
    if (retries >= MAX_RETRIES) {
      throw error;
    }
    const statusCode = error.statusCode || 0;
    // Only retry on transient errors
    if ([429, 500, 502, 503, 529].includes(statusCode)) {
      const delay = BASE_DELAY_MS * Math.pow(2, retries);
      await new Promise(r => setTimeout(r, delay));
      return fetchWithRetry.call(this, url, options, retries + 1);
    }
    throw error; // Non-retryable error
  }
}

const items = $input.all();
const results = [];

for (const item of items) {
  const response = await fetchWithRetry.call(
    this,
    item.json.apiUrl,
    {
      body: item.json.requestBody,
      headers: { 'Content-Type': 'application/json' }
    }
  );
  results.push({ json: { ...item.json, response: response.body } });
}

return results;
```

**Expected result:** HTTP requests are retried with exponential backoff for transient errors, and non-retryable errors fail immediately.

## Complete code example

File: `retry-with-backoff.js`

```javascript
// Code node: Configurable retry with exponential backoff
// Place before any HTTP Request or API node for custom retry logic
// Mode: Run Once for All Items

const CONFIG = {
  maxRetries: 3,
  baseDelayMs: 1000,
  maxDelayMs: 30000,
  retryableStatusCodes: [429, 500, 502, 503, 504, 529],
  jitterMs: 500
};

function getDelay(attempt) {
  const exponentialDelay = CONFIG.baseDelayMs * Math.pow(2, attempt);
  const jitter = Math.random() * CONFIG.jitterMs;
  return Math.min(exponentialDelay + jitter, CONFIG.maxDelayMs);
}

function isRetryable(error) {
  const code = error.statusCode || error.httpCode || 0;
  return CONFIG.retryableStatusCodes.includes(code);
}

async function executeWithRetry(fn, context) {
  let lastError;

  for (let attempt = 0; attempt <= CONFIG.maxRetries; attempt++) {
    try {
      return await fn.call(context);
    } catch (error) {
      lastError = error;

      if (attempt === CONFIG.maxRetries || !isRetryable(error)) {
        throw error;
      }

      const delay = getDelay(attempt);
      console.log(
        `Retry ${attempt + 1}/${CONFIG.maxRetries} ` +
        `after ${delay}ms (status: ${error.statusCode})`
      );
      await new Promise(r => setTimeout(r, delay));
    }
  }

  throw lastError;
}

const items = $input.all();
const results = [];

for (const item of items) {
  const result = await executeWithRetry(async function() {
    return await this.helpers.httpRequest({
      method: item.json.method || 'POST',
      url: item.json.url,
      body: item.json.body,
      headers: item.json.headers || {},
      returnFullResponse: true
    });
  }, this);

  results.push({
    json: {
      ...item.json,
      response: result.body,
      statusCode: result.statusCode
    }
  });
}

return results;
```

## Common mistakes

- **Retrying on all error codes including 400 Bad Request and 401 Unauthorized** — undefined Fix: Only retry on transient errors (429, 500, 502, 503, 529). Client errors like 400 and 401 will fail every retry.
- **Setting too many retries with no delay, causing the API to block your IP** — undefined Fix: Limit retries to 2-3 attempts with at least 1-2 seconds between each. Use exponential backoff for rate-limited APIs.
- **Not saving failed execution data, making manual retry impossible** — undefined Fix: Set EXECUTIONS_DATA_SAVE_ON_ERROR=all in your environment variables to always save failed execution data.
- **Using the Error Trigger to retry every failure without filtering** — undefined Fix: Add an IF node after the Error Trigger to only retry workflows where the error is transient. Some failures should just be logged and reviewed.

## Best practices

- Always save failed execution data (EXECUTIONS_DATA_SAVE_ON_ERROR=all) so you can retry from the UI
- Use Retry On Fail for simple transient errors like network timeouts on API nodes
- Set Wait Between Tries to at least 1000ms to avoid hammering a failing API
- Use an Error Trigger workflow for centralized error handling and notifications
- Only retry on transient error codes (429, 500, 502, 503) — not on 400 or 401 errors
- Add jitter to retry delays to prevent all retries from hitting the API at the same time
- Log retry attempts so you can identify nodes that consistently fail and need fixing

## Frequently asked questions

### Can I retry a workflow with different input data?

The Retry button in the Executions tab uses the original input data. If you need to retry with modified data, open the workflow, paste the corrected data into the trigger node's test data, and run it manually.

### What is the difference between Retry On Fail and the Error Trigger?

Retry On Fail is a per-node setting that retries that specific node automatically before marking the execution as failed. The Error Trigger fires after the entire workflow has failed, giving you a chance to handle the failure in a separate workflow.

### Does Retry On Fail work with the AI Agent node?

Yes, you can enable Retry On Fail on the AI Agent node and its sub-nodes. Set the Wait Between Tries to at least 2000ms for LLM calls that may hit rate limits.

### How many times should I retry a failed API call?

2-3 retries is standard for most APIs. More than 5 retries is usually counterproductive — if the call fails 5 times, the issue is likely not transient and needs manual investigation.

### Can I retry just the failed node instead of the entire workflow?

n8n's retry feature re-runs the entire workflow from the beginning with the original input data. There is no built-in way to retry from a specific node. However, if you enable Save Execution Progress and use the 'Continue (using error output)' On Error setting, failed items can be routed to a retry branch within the same execution.

### Can RapidDev help me build robust error handling for my n8n workflows?

Yes, RapidDev specializes in building production-grade n8n workflows with proper retry logic, exponential backoff, error notifications, and fallback strategies that keep your automations running reliably.

---

Source: https://www.rapidevelopers.com/n8n-tutorial/how-to-retry-failed-workflows-in-n8n
© RapidDev — https://www.rapidevelopers.com/n8n-tutorial/how-to-retry-failed-workflows-in-n8n
