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 →
{
"updatedAt": "2025-12-24T09:18:39.380Z",
"createdAt": "2025-12-23T09:30:28.917Z",
"id": "NOJ7FqVhVLqw0n8D",
"name": "Handle_Error",
"description": null,
"active": false,
"isArchived": false,
"nodes": [
{
"parameters": {},
"type": "n8n-nodes-base.errorTrigger",
"typeVersion": 1,
"position": [
-400,
224
],
"id": "error-trigger-handle-error",
"name": "ErrorTrigger"
},
{
"parameters": {
"jsCode": "// Filter: Skip if this is a parent workflow wrapping a child error\n// Parent errors have errorResponse (the wrapped child error)\nconst errorData = $input.first().json;\nconst error = errorData.execution?.error || {};\n\n// If this error is just wrapping a sub-workflow error, skip it\nif (error.errorResponse) {\n return []; // Return empty to stop flow\n}\n\n// Continue processing - this is the root cause error\nreturn { json: errorData };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-176,
224
],
"id": "filter-duplicates-handle-error",
"name": "FilterDuplicateErrors"
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT \n id,\n payload->>'discord_guild_id' as guild_id,\n payload->>'discord_channel_id' as channel_id,\n payload->>'discord_message_id' as message_id,\n payload->>'clean_text' as clean_text\nFROM events \nWHERE received_at > NOW() - interval '30 seconds'\n AND event_type = 'discord_message'\nORDER BY received_at DESC \nLIMIT 1;",
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.4,
"position": [
48,
224
],
"id": "get-recent-event-handle-error",
"name": "GetRecentEvent",
"alwaysOutputData": true,
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Extract error details and merge with event context\nconst errorData = $('FilterDuplicateErrors').first().json;\nconst eventData = $json || {};\n\nconst execution = errorData.execution || {};\nconst workflow = errorData.workflow || {};\nconst error = execution.error || {};\n\n// Get the node that failed\nconst failedNode = error.node?.name || execution.lastNodeExecuted || 'Unknown';\nconst errorMessage = error.message || 'No error message';\n\n// Get workflow info\nconst workflowName = workflow.name || 'Unknown';\nconst executionId = execution.id || 'N/A';\n\n// Get Discord context from recent event\nconst guildId = eventData.guild_id || null;\nconst channelId = eventData.channel_id || null;\nconst messageId = eventData.message_id || null;\nconst cleanText = eventData.clean_text || '';\n\n// Try to extract from error URL if available\nlet extractedChannelId = channelId;\nlet extractedMessageId = messageId;\n\nif (!channelId && error.context?.request?.uri) {\n const uri = error.context.request.uri;\n // Parse: https://discord.com/api/v10/channels/{channel_id}/messages/{message_id}/...\n const match = uri.match(/channels\\/([0-9]+)\\/messages\\/([0-9]+)/);\n if (match) {\n extractedChannelId = match[1];\n extractedMessageId = match[2];\n }\n}\n\n// Build condensed Discord message\nlet content = `\u274c **${workflowName}** \u2192 ${failedNode}\\n`;\ncontent += `${errorMessage}`;\n\nif (cleanText) {\n const preview = cleanText.length > 50 ? cleanText.substring(0, 50) + '...' : cleanText;\n content += `\\n\ud83d\udcdd \"${preview}\"`;\n}\n\ncontent += `\\n\\`exec:${executionId}\\``;\n\n// Truncate if needed (Discord 2000 char limit)\nif (content.length > 1900) {\n content = content.substring(0, 1900) + '...';\n}\n\nreturn {\n json: {\n content: content,\n guild_id: guildId || process.env.DISCORD_GUILD_ID,\n channel_id: extractedChannelId,\n message_id: extractedMessageId,\n can_react: !!(extractedChannelId && extractedMessageId)\n }\n};"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
272,
224
],
"id": "format-error-handle-error",
"name": "FormatErrorMessage"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "can-react-condition",
"leftValue": "={{ $json.can_react }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
496,
224
],
"id": "check-can-react-handle-error",
"name": "CanReact?"
},
{
"parameters": {
"method": "PUT",
"url": "=https://discord.com/api/v10/channels/{{ $json.channel_id }}/messages/{{ $json.message_id }}/reactions/%E2%9D%8C/@me",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "discordBotApi",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
720,
144
],
"id": "add-error-reaction-handle-error",
"name": "Add\u274cReaction",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
},
"continueOnFail": true
},
{
"parameters": {
"method": "DELETE",
"url": "=https://discord.com/api/v10/channels/{{ $json.channel_id }}/messages/{{ $json.message_id }}/reactions/%F0%9F%94%B5/@me",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "discordBotApi",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
944,
144
],
"id": "remove-blue-reaction-handle-error",
"name": "Remove\ud83d\udd35Reaction",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
},
"continueOnFail": true
},
{
"parameters": {
"resource": "message",
"guildId": {
"__rl": true,
"value": "={{ $env.DISCORD_GUILD_ID }}",
"mode": "id"
},
"channelId": {
"__rl": true,
"value": "={{ $env.DISCORD_CHANNEL_KAIRON_LOGS }}",
"mode": "id"
},
"content": "={{ $('FormatErrorMessage').item.json.content }}",
"options": {}
},
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [
1392,
224
],
"id": "send-error-discord-handle-error",
"name": "SendErrorToLogs",
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 1000,
"credentials": {
"discordBotApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "append",
"numberInputs": 2
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1168,
224
],
"id": "merge-paths-handle-error",
"name": "MergePaths"
}
],
"connections": {
"ErrorTrigger": {
"main": [
[
{
"node": "FilterDuplicateErrors",
"type": "main",
"index": 0
}
]
]
},
"FilterDuplicateErrors": {
"main": [
[
{
"node": "GetRecentEvent",
"type": "main",
"index": 0
}
]
]
},
"GetRecentEvent": {
"main": [
[
{
"node": "FormatErrorMessage",
"type": "main",
"index": 0
}
]
]
},
"FormatErrorMessage": {
"main": [
[
{
"node": "CanReact?",
"type": "main",
"index": 0
}
]
]
},
"CanReact?": {
"main": [
[
{
"node": "Add\u274cReaction",
"type": "main",
"index": 0
}
],
[
{
"node": "MergePaths",
"type": "main",
"index": 1
}
]
]
},
"Add\u274cReaction": {
"main": [
[
{
"node": "Remove\ud83d\udd35Reaction",
"type": "main",
"index": 0
}
]
]
},
"Remove\ud83d\udd35Reaction": {
"main": [
[
{
"node": "MergePaths",
"type": "main",
"index": 0
}
]
]
},
"MergePaths": {
"main": [
[
{
"node": "SendErrorToLogs",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false
},
"staticData": null,
"meta": null,
"versionId": "98a19fff-c4cf-4aaa-9a07-ebd60bdb0627",
"activeVersionId": null,
"versionCounter": 131,
"triggerCount": 0,
"shared": [
{
"updatedAt": "2025-12-23T09:30:28.917Z",
"createdAt": "2025-12-23T09:30:28.917Z",
"role": "workflow:owner",
"workflowId": "NOJ7FqVhVLqw0n8D",
"projectId": "erM3nntdLL53noWi",
"project": {
"updatedAt": "2025-12-23T09:23:39.658Z",
"createdAt": "2025-12-23T09:16:56.460Z",
"id": "erM3nntdLL53noWi",
"name": "Chris Irineo <chriskevini@gmail.com>",
"type": "personal",
"icon": null,
"description": null,
"projectRelations": [
{
"updatedAt": "2025-12-23T09:16:56.460Z",
"createdAt": "2025-12-23T09:16:56.460Z",
"userId": "2a851a2d-b7e5-4b3c-aefb-6eaaa79e0659",
"projectId": "erM3nntdLL53noWi",
"user": {
"updatedAt": "2025-12-24T08:40:46.063Z",
"createdAt": "2025-12-23T09:16:54.881Z",
"id": "2a851a2d-b7e5-4b3c-aefb-6eaaa79e0659",
"email": "chriskevini@gmail.com",
"firstName": "Chris",
"lastName": "Irineo",
"personalizationAnswers": {
"version": "v4",
"personalization_survey_submitted_at": "2025-12-23T09:23:43.723Z",
"personalization_survey_n8n_version": "1.123.5"
},
"settings": {
"userActivated": true,
"firstSuccessfulWorkflowId": "CgUAxK0i4YhrZ2Wp",
"userActivatedAt": 1766487000077,
"easyAIWorkflowOnboarded": true
},
"disabled": false,
"mfaEnabled": false,
"lastActiveAt": "2025-12-24",
"isPending": false
}
}
]
}
}
],
"tags": [],
"activeVersion": null
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
discordBotApipostgres
About this workflow
Handle_Error. Uses errorTrigger, postgres, httpRequest, discord. Event-driven trigger; 9 nodes.
Source: https://github.com/chriskevini/kairon/blob/ab924f228ceb22522b9a4dfa1ab4589eb86273ad/n8n-workflows/Handle_Error.json — original creator credit. Request a take-down →