AutomationFlowsSlack & Telegram › Notify on Workflow Errors via Slack with Discord Fallback

Notify on Workflow Errors via Slack with Discord Fallback

By鈴木光輝 @koki-suzuki on n8n.io

This workflow catches failures from any other n8n workflow via the built-in Error Trigger, posts a readable summary to Slack, and automatically falls back to Discord if the Slack notification itself fails. Receives failure details from n8n's Error Trigger: workflow name, failing…

Event trigger★★★★☆ complexity17 nodesError TriggerHTTP Request
Slack & Telegram Trigger: Event Nodes: 17 Complexity: ★★★★☆ Added:
Notify on Workflow Errors via Slack with Discord Fallback — n8n workflow card showing Error Trigger, HTTP Request integration

This workflow corresponds to n8n.io template #18122 — we link there as the canonical source.

This workflow follows the Error Trigger → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "oc1Ugtl0k5jdeLWX",
  "name": "Notify Slack on workflow errors, with a Discord fallback",
  "tags": [],
  "nodes": [
    {
      "id": "pub002-sticky-main",
      "name": "Sticky Note: Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        -1136
      ],
      "parameters": {
        "width": 2900,
        "height": 520,
        "content": "## Error notifier with dedup and a fallback channel\n\nAttach this workflow as the \"Error Workflow\" (Settings \u2192 Error Workflow) on any of your other n8n workflows. When one of them fails, this workflow receives the error via n8n's built-in Error Trigger, skips duplicate notifications for the same execution, and posts a readable summary to Slack. If the Slack post itself fails (bad URL, Slack outage, etc.), it automatically falls back to Discord instead of failing silently.\n\n### Before you activate\n1. Create a Slack Incoming Webhook (no Slack app/OAuth needed) and paste its URL into the \"Set: Slack webhook URL\" node.\n2. Create a Discord Incoming Webhook (Channel Settings \u2192 Integrations \u2192 Webhooks) and paste its URL into the \"Set: Discord webhook URL\" node.\n3. Activate this workflow, then open the workflow(s) you want monitored \u2192 Settings \u2192 Error Workflow \u2192 select this workflow.\n\n### Note on deduplication\nDeduplication uses n8n's workflow static data, which is only persisted for executions triggered automatically (not manual test runs) \u2014 this is expected and matches how Error Workflows actually run in production."
      },
      "typeVersion": 1
    },
    {
      "id": "pub002-sticky-step1",
      "name": "Sticky Note: Step 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        -528
      ],
      "parameters": {
        "width": 650,
        "height": 220,
        "content": "Step 1 \u2014 Detect & de-duplicate\n\nReceives the error from n8n's Error Trigger, extracts the workflow name, failing node, error message and execution URL, and checks whether this exact execution was already notified (skips repeat notifications from multi-failure scenarios)."
      },
      "typeVersion": 1
    },
    {
      "id": "pub002-sticky-step2",
      "name": "Sticky Note: Step 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        -528
      ],
      "parameters": {
        "width": 650,
        "height": 220,
        "content": "Step 2 \u2014 Notify Slack\n\nPosts a formatted error summary to Slack via an Incoming Webhook. If the request fails for any reason, control passes to the fallback step instead of the notification being silently lost."
      },
      "typeVersion": 1
    },
    {
      "id": "pub002-sticky-step3",
      "name": "Sticky Note: Step 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        -528
      ],
      "parameters": {
        "width": 650,
        "height": 220,
        "content": "Step 3 \u2014 Fallback to Discord\n\nOnly runs if the Slack notification failed. Posts the same error summary to a Discord channel via an Incoming Webhook, so a broken Slack integration never means you hear nothing about a failure."
      },
      "typeVersion": 1
    },
    {
      "id": "pub002-error-trigger",
      "name": "Error Trigger",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        -800,
        0
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "pub002-check-dup",
      "name": "Check duplicate & summarize error",
      "type": "n8n-nodes-base.code",
      "notes": "Uses $getWorkflowStaticData('global') to remember which execution IDs have already been notified. Static data only persists for automatically-triggered executions (not manual test runs) \u2014 confirmed against docs.n8n.io, 2026-08-12. That's fine here since Error Workflows only ever run automatically in real use.",
      "position": [
        -560,
        0
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst staticData = $getWorkflowStaticData('global');\nif (!Array.isArray(staticData.notifiedExecutionIds)) {\n  staticData.notifiedExecutionIds = [];\n}\n\nconst executionId = String((data.execution && data.execution.id) || '');\nconst alreadyNotified = Boolean(executionId) && staticData.notifiedExecutionIds.includes(executionId);\n\nif (!alreadyNotified && executionId) {\n  staticData.notifiedExecutionIds.push(executionId);\n  // Keep static data well under the 64KB cap by only remembering the most recent 200 execution IDs.\n  if (staticData.notifiedExecutionIds.length > 200) {\n    staticData.notifiedExecutionIds = staticData.notifiedExecutionIds.slice(-200);\n  }\n}\n\nconst workflowName = (data.workflow && data.workflow.name) || 'Unknown workflow';\nconst errorMessage = (data.execution && data.execution.error && data.execution.error.message) || 'No error message provided';\nconst lastNode = (data.execution && data.execution.lastNodeExecuted) || 'Unknown node';\nconst mode = (data.execution && data.execution.mode) || 'unknown';\nconst executionUrl = (data.execution && data.execution.url) || '';\n\nreturn [{\n  json: { alreadyNotified, executionId, workflowName, errorMessage, lastNode, mode, executionUrl }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "pub002-if-dup",
      "name": "Already notified?",
      "type": "n8n-nodes-base.if",
      "position": [
        -320,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "pub002-cond-dup",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.alreadyNotified === true }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "pub002-noop-skip",
      "name": "Skip: already notified for this execution",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -64,
        304
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "pub002-set-slack-url",
      "name": "Set: Slack webhook URL",
      "type": "n8n-nodes-base.set",
      "notes": "Placeholder value \u2014 not a real webhook URL. Create your own Slack Incoming Webhook and paste the URL here before activating.",
      "position": [
        -64,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-slack-url",
              "name": "slackWebhookUrl",
              "type": "string",
              "value": "https://hooks.slack.com/services/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"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "pub002-build-slack",
      "name": "Build Slack message",
      "type": "n8n-nodes-base.code",
      "position": [
        208,
        0
      ],
      "parameters": {
        "jsCode": "const config = $input.first().json;\nconst err = $('Check duplicate & summarize error').first().json;\n\nconst lines = [\n  `:rotating_light: *${err.workflowName}* failed`,\n  `*Node:* ${err.lastNode}`,\n  `*Error:* ${err.errorMessage}`\n];\nif (err.executionUrl) lines.push(`*Execution:* ${err.executionUrl}`);\nlines.push(`*Mode:* ${err.mode}`);\n\nreturn [{ json: { slackWebhookUrl: config.slackWebhookUrl, slackRequestBody: { text: lines.join('\\n') } } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "pub002-notify-slack",
      "name": "Notify Slack",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        448,
        0
      ],
      "parameters": {
        "url": "={{ $json.slackWebhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ $json.slackRequestBody }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "pub002-if-slack-ok",
      "name": "Slack notify succeeded?",
      "type": "n8n-nodes-base.if",
      "notes": "Checks the actual response body, not just the absence of a thrown error. Slack's Incoming Webhook returns the literal text \"ok\" on success (confirmed via a real test send, 2026-08-12). An invalid/malformed webhook URL does NOT reliably produce an HTTP error \u2014 it can redirect to Slack's own developer docs page (HTTP 200, HTML body), which a check that only looks for $json.error would wrongly treat as success. This was an actual bug found during testing.",
      "position": [
        688,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "pub002-cond-slack-ok",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.error ? 'error' : $json.data }}",
              "rightValue": "ok"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "pub002-noop-done-slack",
      "name": "Done: Slack notified",
      "type": "n8n-nodes-base.noOp",
      "position": [
        928,
        -144
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "pub002-set-discord-url",
      "name": "Set: Discord webhook URL",
      "type": "n8n-nodes-base.set",
      "notes": "Placeholder value \u2014 not a real webhook URL. In Discord: Channel Settings \u2192 Integrations \u2192 Webhooks \u2192 New Webhook \u2192 Copy Webhook URL, then paste it here before activating.",
      "position": [
        928,
        160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-discord-url",
              "name": "discordWebhookUrl",
              "type": "string",
              "value": "https://discord.com/api/webhooks/1536816493516300288/-DvmQxU_DYfaXCxuhLxVMGVAvGjNSVPlhr6PSdhO7rZybRbfT5FZGUAFaCJeaomu8LNV"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "pub002-build-discord",
      "name": "Build Discord message",
      "type": "n8n-nodes-base.code",
      "position": [
        1168,
        160
      ],
      "parameters": {
        "jsCode": "const config = $input.first().json;\nconst err = $('Check duplicate & summarize error').first().json;\n\nconst lines = [\n  `\ud83d\udea8 **${err.workflowName}** failed`,\n  `Node: ${err.lastNode}`,\n  `Error: ${err.errorMessage}`\n];\nif (err.executionUrl) lines.push(`Execution: ${err.executionUrl}`);\nlines.push(`Mode: ${err.mode}`);\n\nreturn [{ json: { discordWebhookUrl: config.discordWebhookUrl, discordRequestBody: { content: lines.join('\\n') } } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "pub002-notify-discord",
      "name": "Notify Discord (fallback)",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "If this also fails, the execution list in n8n itself remains the last resort record of the failure \u2014 there is no further fallback beyond Discord in this template.",
      "position": [
        1408,
        160
      ],
      "parameters": {
        "url": "={{ $json.discordWebhookUrl }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ $json.discordRequestBody }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "pub002-noop-done-discord",
      "name": "Done: Discord fallback notified",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1648,
        160
      ],
      "parameters": {},
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "c57f15b0-a54a-4488-a41d-c6179d0b1bc4",
  "nodeGroups": [],
  "connections": {
    "Notify Slack": {
      "main": [
        [
          {
            "node": "Slack notify succeeded?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Trigger": {
      "main": [
        [
          {
            "node": "Check duplicate & summarize error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Already notified?": {
      "main": [
        [
          {
            "node": "Skip: already notified for this execution",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set: Slack webhook URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Slack message": {
      "main": [
        [
          {
            "node": "Notify Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Discord message": {
      "main": [
        [
          {
            "node": "Notify Discord (fallback)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set: Slack webhook URL": {
      "main": [
        [
          {
            "node": "Build Slack message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack notify succeeded?": {
      "main": [
        [
          {
            "node": "Done: Slack notified",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set: Discord webhook URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set: Discord webhook URL": {
      "main": [
        [
          {
            "node": "Build Discord message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Discord (fallback)": {
      "main": [
        [
          {
            "node": "Done: Discord fallback notified",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check duplicate & summarize error": {
      "main": [
        [
          {
            "node": "Already notified?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow catches failures from any other n8n workflow via the built-in Error Trigger, posts a readable summary to Slack, and automatically falls back to Discord if the Slack notification itself fails. Receives failure details from n8n's Error Trigger: workflow name, failing…

Source: https://n8n.io/workflows/18122/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

Track all n8n workflow failures with automatic error capture, severity classification, duplicate detection, Slack alerting, performance metrics, and log retention.

Error Trigger, HTTP Request, Slack
Slack & Telegram

Weather Bot - Main Handler. Uses telegramTrigger, googleSheets, telegram, httpRequest. Event-driven trigger; 65 nodes.

Telegram Trigger, Google Sheets, Telegram +1
Slack & Telegram

This n8n workflow provides automated monitoring of Public Key Infrastructure (PKI) components including CA certificates, Certificate Revocation Lists (CRLs), and associated web services. It extracts c

Write Binary File, Execute Command, HTTP Request
Slack & Telegram

This workflow captures n8n workflow execution errors, classifies and deduplicates them, logs incidents to a Notion database, and routes high-severity alerts to a Slack channel, with an optional daily

Error Trigger, Notion, Slack
Slack & Telegram

This n8n workflow automates the process of scraping Google Play Store reviews, analyzing app performance, and sending alerts for low-rated applications. It integrates with Bright Data for web scraping

Form Trigger, HTTP Request, Google Sheets +1