Secure and Digest n8n Failures

Secure an n8n archive workflow with deduplicated failure digests.

Introduction

30 Second Summary

When a background task fails quietly, the first clue is often a missing result. Repeated alerts create the opposite problem by burying the failure that needs attention.

In this project, you will harden your existing n8n archive pipeline for authenticated production use. Its reusable failure path will turn repeated technical errors into a retry-safe Discord digest.

What You'll Build

You will watch repeated copies of a controlled archive failure collapse into one retryable record that reaches Discord in a compact digest.

By the end of this project, you'll have:

  • Header authentication that stops requests without the shared secret before they create an archive execution. Authenticated jobs still produce the normal Discord result.
  • Clear failure routing that lets you inspect a controlled technical failure in the execution history. A processing result stays on a successful no-alert path.
  • Deduplicated failure digests where repeated failures collapse into one unsent Data Table row. Discord receives up to five failures in one digest before only the delivered fingerprints become sent.
  • Secret Mission: Force the digest delivery path to fail. Prove the selected rows remain retryable before recovering the branch and delivering them successfully.

Are there any prerequisites?

This project builds on Set Up Your Free Local n8n Lab, Build a Webhook-to-Discord Automation, Containerize a Python Archive Processor, and Connect n8n to Python Archive API.

Your existing Docker lab, archive processor, production workflow, PowerShell sender, and Discord webhook should still be available.

Before We Start

This checkpoint locks in why you are hardening the existing archive automation before you change it. The key distinction separates a valid non-ready processor result from a technical execution failure that needs durable reporting.

Secure the Production Webhook

A production webhook is an entry point into your archive pipeline. Anyone who knows its current URL can start the workflow.

In this step, you'll add Header authentication to the existing n8n workflow. You'll prove that unauthenticated calls are rejected while authenticated ready jobs still reach Discord.

In this step, get ready to:
  • Verify that the current archive route still delivers its ready result to Discord.
  • Protect the existing Webhook node with a credential-backed shared secret.
  • Update the Windows PowerShell sender to supply the secret at runtime.
Confirm the existing pipeline

A security change needs a reliable baseline. First, confirm that the retained services still support the working processor-backed route.

  • Switch back to Docker Desktop from your existing local lab.
  • Confirm the retained Compose project shows n8n running.
  • Confirm the archive-processor container is running.
  • Confirm the archive-automation network is available.

The workflow engine and processor are both available on the retained network. That gives the existing archive route everything it needs to run.

  • Press the Windows key to open search.
  • Type Firefox into search.
  • Press Enter to open Firefox.
  • Return to the local n8n address from your retained lab.
  • Sign in to your local n8n instance.
  • Open the existing published archive workflow.
  • Confirm the ready-result Discord node still uses the existing Discord Webhook credential.

The workflow is published with its processor-backed route intact. Its Discord credential remains selected without exposing the webhook URL.

  • Press the Windows key to open search.
  • Type Windows PowerShell into search.
  • Press Enter to open Windows PowerShell.
  • Run one unchanged production request with the retained sender from the earlier archive project.
  • Return to your existing Discord channel.

You now have a trustworthy baseline: the processor-backed route still delivers its ready result to Discord.

Add Header authentication

Header authentication checks a shared secret before a production request can start the workflow. n8n stores the required header name and secret value inside a credential.

Why Header authentication?

Header authentication fits this project because the existing PowerShell sender needs one shared secret. Basic authentication would add credentials this local caller does not need.

JWT would introduce additional identity setup. A shared header creates the required boundary with fewer moving parts.

You are about to handle a shared secret. The value stays in the n8n credential while the sender asks for it only when a request runs.

  • Open the existing Webhook node on the archive workflow canvas.
  • Set Authentication to Header auth.

The Webhook node now reveals a credential selector for the authentication boundary.

  • Create a Webhook Header Auth credential from the credential selector.
  • Name the credential Archive Webhook Header.

The credential editor now identifies this secret as the one used by the archive webhook.

  • Set Name to X-Archive-Key.
  • Enter a private learner-generated secret that is unique to this webhook in the Value field.

Both required credential fields are now populated. The header name remains visible while the shared secret stays inside the credential editor.

  • Save the credential.

The credential selector now includes Archive Webhook Header as a reusable credential.

  • Select Archive Webhook Header for the Webhook node.
  • Publish the archive workflow.

The workflow now shows its published state with Header auth attached to the production Webhook node.

Update the PowerShell sender safely

The sender keeps the shared secret out of its saved script by reading it at runtime. It converts the masked input into the header required by the Webhook node.

  • Return to the saved PowerShell sender from the earlier archive project.
  • Find its existing Invoke-RestMethod request.

The request line is the point where the sender can attach its authenticated header.

  • Insert runtime secret handling immediately above that request by adding this code:
$secureToken = Read-Host 'Enter the archive webhook token' -AsSecureString
$token = [System.Net.NetworkCredential]::new('', $secureToken).Password
$headers = @{ 'X-Archive-Key' = $token }

What does this sender code do?

  • Read-Host masks the typed secret. $secureToken holds the resulting SecureString.
  • NetworkCredential converts the SecureString for the request. $token holds that runtime value.
  • $headers maps X-Archive-Key to the runtime token expected by the Webhook node.
  • Save the PowerShell sender.
  • Keep the existing Invoke-RestMethod request free of -Headers $headers for the first check.

Before you run the sender, do you expect n8n to create an archive execution when the required header is missing?

  • Run the saved sender using the same PowerShell command from the earlier archive project.
  • Enter your learner-generated secret when PowerShell prompts for it.
  • Return to the archive workflow's Executions view in Firefox.
  • Refresh the execution list.

PowerShell reports that the request was rejected. You will see no new archive execution because authentication stopped the request before the workflow started.

  • Add -Headers $headers to the existing Invoke-RestMethod request.
  • Save the PowerShell sender.

Before you run it again, do you expect the same secret to pass the new authentication boundary?

  • Run the saved sender again.
  • Enter the same learner-generated secret when PowerShell prompts for it.
  • Close PowerShell after the request completes.
  • Return to the archive workflow's Executions view.
  • Open the newest successful production execution.

You will see the execution follow the Process Archive Job route through the ready-status path.

  • Return to your existing Discord channel.

Strong result. Your production webhook now rejects missing secrets before n8n creates an archive execution.

The authenticated sender still calls the processor. Its ready result still reaches Discord through the existing credential.

Request still failing?

  • Confirm the Webhook node still shows Header auth if an unauthenticated request creates an execution. Publish the workflow again after selecting the credential.
  • Confirm the header name is exactly X-Archive-Key if the authenticated request is rejected. Retype the same secret at the PowerShell prompt.
  • Confirm the existing Discord Webhook credential remains selected if the execution succeeds without a Discord result.

Help me debug my authenticated archive webhook request.

Your archive pipeline now has an authentication boundary without losing its working ready path. Next up, you'll capture a controlled technical failure with a reusable error workflow.

Catch a Controlled Failure

Your production webhook now rejects callers that do not provide the shared header secret. Header authentication protects the start of each archive job.

An authenticated processor can still fail after the execution begins. The current success route has no reusable technical-failure alert.

In this step, you will route that failure into a reusable n8n error workflow. The handler sends an immediate Discord alert with the evidence needed to investigate.

In this step, get ready to:
  • Create a reusable error workflow that normalizes failure details.
  • Add a controlled technical-failure route to the archive workflow.
  • Trigger a failed production execution that sends an immediate Discord alert.
Build the reusable error workflow

An error workflow receives structured information when an automatic execution fails. Its first node is an Error Trigger so the same handler can support other workflows later.

  • Create a workflow from the workflows page named Archive Automation Error Handler.
  • Add Error Trigger as the first node.
  • Add Edit Fields after Error Trigger.
  • Map workflow.name into a new output field named workflowName.
  • Map execution.lastNodeExecuted into a new output field named lastNode.
  • Map execution.error.message into a new output field named errorMessage.
  • Map execution.url into a new output field named executionUrl.

What Does the Handler Capture?

The normalized fields identify the affected workflow. They also preserve the failed node plus its error message.

The execution URL gives you a direct route back to the saved failure. That link makes the alert useful during an investigation.

Error Trigger responds to automatic workflow failures. A manual editor run does not activate it.

  • Add a Discord node after Edit Fields.
  • Choose Message as the Discord resource.
  • Choose Send as the operation.
  • Select the existing Discord Webhook credential from the ready-result path.
  • Insert workflowName on the first message line.
  • Insert lastNode on the second message line.
  • Insert errorMessage on the third message line.
  • Insert executionUrl on the fourth message line.

The message editor now contains the four normalized details. The webhook URL remains protected inside the existing credential.

  • Save Archive Automation Error Handler.
  • Confirm the canvas shows Error Trigger flowing through Edit Fields into Discord.

Your reusable handler is now ready to receive an automatic failure from the archive workflow.

Handler Canvas Looks Incomplete?

  • Confirm Error Trigger is the first node in Archive Automation Error Handler.
  • Check that Edit Fields outputs all four normalized fields.
  • Make sure Discord uses the existing credential from the ready-result path.

Help me check my reusable n8n error workflow configuration.

Add the controlled failure route

A controlled failure gives you a repeatable way to test the handler. The new Boolean switch follows the incoming request without changing the existing ready path.

  • Switch back to the existing archive workflow.
  • Add a Boolean output field named simulateFailure to the existing Edit Fields node.
  • Configure simulateFailure to become true only when the incoming body contains Boolean true.

The Edit Fields configuration now carries the failure switch alongside the existing archive-job data.

  • Insert an If node before Process Archive Job.
  • Configure its Boolean condition so simulateFailure is true.

The If node now exposes separate true and false outputs for the two archive paths.

  • Add a Stop And Error node on the true side.
  • Name the node Controlled Archive Failure.

The true side of the canvas now has a dedicated failure node that is easy to identify in execution history.

  • Select Error Message in the Stop And Error node.
  • Enter Controlled archive failure requested as the error message.

The failure node now has the exact message that the reusable handler will capture.

  • Connect the true output of If to Controlled Archive Failure.
  • Connect the false output of If to Process Archive Job.

The canvas now has a deliberate failure path plus the unchanged processor path.

  • Save the archive workflow.

Why Use Stop And Error?

Stop And Error deliberately marks the execution as failed. That technical failure activates the selected error workflow during a production run.

The false route keeps normal archive jobs connected to the processor. Existing ready results can still continue to the Discord success report.

Failure Route Looks Wrong?

  • Check that If reads the Boolean simulateFailure field.
  • Confirm the true output reaches Controlled Archive Failure.
  • Confirm the false output reaches Process Archive Job.

Help me debug the true and false branches in my archive workflow.

Link and trigger the handler

The archive workflow must explicitly name its error workflow. Saving failed production executions preserves the details that the handler sends to Discord.

  • Open the archive workflow settings.
  • Select Archive Automation Error Handler for Error Workflow.

The settings panel now identifies the reusable handler that receives technical failures.

  • Enable Save failed production executions.
  • Publish the archive workflow.

The production workflow is now linked to the handler. Its failed executions can retain an execution URL for investigation.

The Error Trigger requires an automatic failure, so this test uses the published webhook through the sender from earlier.

  • Return to the saved Windows PowerShell sender from earlier.
  • Add simulateFailure to the existing request body with the Boolean value $true.

This is an intentional failure test. Before you run the sender, consider whether the authenticated request reaches the processor or stops in the new branch.

  • Run the existing PowerShell sender.
  • Enter the same archive webhook secret at the secure prompt.

The authenticated request reports a failed call. That result is expected because the true route deliberately stopped the production execution.

Before you inspect the evidence, predict which failure details the execution and alert should share.

  • Return to Firefox with your local n8n instance.
  • Open the archive workflow's Executions tab.
  • Open the newest production execution marked Failed.
  • Inspect the last failed node.
  • Inspect the saved error message.
  • Return to Discord.
  • Open the newest technical-failure alert.
  • Compare its normalized details with the failed execution.

The production execution shows the Failed status.

Its last failed node is Controlled Archive Failure.

Its saved message is Controlled archive failure requested.

The Discord alert identifies the same workflow. It also carries the matching node plus its error message.

That is the failure boundary working. Authenticated technical failures now leave inspectable evidence.

Your archive automation can now report a controlled technical failure through one reusable handler. Next up, you will keep valid non-ready processor responses on a normal business path.

Separate Business States

Your error handler now catches genuine n8n execution failures. However, a processor response with status processing still means the request completed successfully.

This step gives that business state a normal destination before you compare it with repeated technical failures. The comparison shows whether your current Discord alerts remain useful when the same fault happens more than once.

In this step, get ready to:
  • Route successful non-ready processor responses to Not Ready Result.
  • Prove a processing response completes through a normal no-alert path.
  • Repeat the controlled technical failure to evaluate the immediate alert behavior.
Route non-ready results normally

The ready-status If node evaluates the business state after the processor responds successfully. Its false output needs a normal destination so unfinished jobs remain inspectable without becoming technical failures.

  • Return to the existing archive workflow from earlier in the n8n editor.
  • Connect the false output of the ready-status If node to an Edit Fields node.
  • Name the new node Not Ready Result.
  • Set resultType to not_ready.
  • Preserve the returned job identifier by mapping the identifier field produced by Process Archive Job.
  • Preserve the returned status by mapping its existing field without renaming it.
  • Leave the output of Not Ready Result unconnected.

Your canvas now shows two normal business routes after Process Archive Job. Ready results continue toward the existing success report while non-ready results end at Not Ready Result.

Test a processing response

Pinned data lets you replay a processor response without changing the Python service. This isolates the ready-status routing logic for a safe manual test.

  • Select Process Archive Job on the workflow canvas.
  • Pin its latest successful output.
  • Change only the pinned status value from ready to processing.

Before you execute the downstream route, do you think processing should complete successfully or enter the error workflow?

  • Execute the downstream route from the ready-status If node.

You should see the manual execution complete successfully through Not Ready Result. Discord receives no technical-failure alert.

Why is processing successful?

The processor returned data successfully, so the workflow still has a valid business result. The processing status only says the archive is not ready yet.

Technical failures interrupt node execution and enter the reusable error workflow. Business states continue through ordinary branches.

Did the ready route run instead?

  • Confirm the pinned status value is exactly processing.
  • Confirm the false output of the ready-status If node connects to Not Ready Result.
  • Confirm Not Ready Result has no connection to Stop And Error.

Help me diagnose why my pinned processing response did not reach Not Ready Result.

  • Unpin the output from Process Archive Job.

The processor node now uses live output again. Your production tests can continue without development data affecting the canvas.

Expose the duplicate alert problem

A production request with simulateFailure set to $true still follows Controlled Archive Failure. The existing PowerShell sender asks for the header secret during each run.

Before you send the same failure twice, how many Discord messages do you think two identical failed executions will create?

  • Return to the existing PowerShell sender from earlier.
  • Set simulateFailure to $true in the existing JSON body.
  • Run the sender once against the production webhook.
  • Enter the archive webhook secret when the first prompt appears.
  • Run the sender a second time against the same production webhook.
  • Enter the archive webhook secret when the second prompt appears.
  • Open the archive workflow's Executions tab to compare the two production runs.
  • Open Discord to count the new technical-failure alerts.

You should see two failed production executions with the same workflow, failed node, and error message. You should also see two immediate Discord alerts for the same technical problem.

That duplication is the limitation you needed to expose. Each technical failure is recorded correctly, but each execution creates its own notification.

Only seeing one alert?

  • Confirm each sender run used the production webhook.
  • Confirm each sender run supplied $headers.
  • Confirm simulateFailure was $true for both requests.

Help me trace why two controlled production failures did not create two Discord alerts.

That boundary is doing its job. Next, you will replace repeated immediate alerts with durable failure records.

Deduplicate Failure Records

You proved that successful processing responses stay on a normal business path. You also exposed the next problem when two identical technical failures produced two identical Discord alerts.

A Data Table gives the reusable handler durable state across workflows. In this step, you will assign each failure a stable failure fingerprint so one repeating fault refreshes one unsent record.

In this step, get ready to:
  • Create the Archive Failure Log table with fields for normalized failures.
  • Replace immediate alert delivery with a fingerprint-matched upsert.
  • Trigger duplicate failures to prove they collapse into one unsent row.
Create the failure table

The table schema gives every technical failure the same shape. Its sent field also records whether a future digest has delivered that failure.

  • Return to your local n8n instance in Firefox.
  • Select the Personal project.
  • Select the Data tables tab.

You should see the project-level area for structured workflow data.

  • Create a table from scratch named Archive Failure Log.

You should now see an empty table named Archive Failure Log.

  • Add a String column named fingerprint.
  • Add a String column named workflowName.

The table should list both columns beside its default fields.

  • Add a String column named lastNode.
  • Add a String column named errorMessage.

The schema can now identify the workflow location and the technical problem.

  • Add a String column named executionUrl.
  • Add a Boolean column named sent.

Your finished schema should contain five String columns and one Boolean column.

Replace immediate delivery with an upsert

An upsert updates a row when its matching condition succeeds. It creates a row when no match exists.

  • Return to the existing Archive Automation Error Handler workflow.
  • Select its existing Edit Fields node.
  • Add a field named fingerprint that combines workflowName, lastNode, and errorMessage in a stable order.

The normalized event should now include a fingerprint field alongside the four existing fields.

  • Disconnect the immediate Discord alert node from the active handler path.
  • Add a Data Table node after Edit Fields.

The active path should now flow from normalization into table storage.

  • Set the Data Table resource to Row.
  • Set the operation to Upsert.

The node should now show controls for choosing a table and defining the matching condition.

  • Select Archive Failure Log as the target table.
  • Match the table's fingerprint column against the incoming fingerprint value.

This condition makes the fingerprint the identity of a recurring technical failure.

  • Map the incoming fingerprint value to the table's fingerprint column.
  • Map the incoming workflowName value to the table's workflowName column.

The upsert can now identify the failure and preserve its workflow name.

  • Map the incoming lastNode value to the table's lastNode column.
  • Map the incoming errorMessage value to the table's errorMessage column.

Each stored record should now describe where the execution stopped and why it failed.

  • Map the incoming executionUrl value to the table's executionUrl column.
  • Set the table's sent value to false.

A new or recurring failure now becomes retryable until a later workflow delivers it.

  • Save the Archive Automation Error Handler workflow.

How does the upsert stop duplicates?

Identical failures produce the same fingerprint because they share the same workflow name, last node, and error message. The upsert finds that fingerprint and refreshes its existing row.

A genuinely different failure produces a different fingerprint. That failure earns its own row for later delivery.

Prove one fault creates one row

A deterministic fingerprint proves its value when the same production failure happens more than once. The execution history should record both failures while the table retains one retryable record.

Before you run the requests, how many table rows do you expect the same workflow, node, and message to produce?

  • Return to the existing PowerShell sender.
  • Submit one authenticated production request with simulateFailure = $true.
  • Return to the archive workflow's Executions tab.

You should see one new Failed production execution ending at Controlled Archive Failure.

  • Return to the existing PowerShell sender.
  • Submit the same authenticated controlled-failure payload again.
  • Return to the archive workflow's Executions tab.

You should see a second Failed production execution with the same failed node and error message.

  • Return to Archive Failure Log in the Personal project's Data tables tab.
  • Filter the table for the fingerprint produced by Controlled Archive Failure.

You should see one matching row. Its sent value should be false.

  • Check the existing Discord channel for messages posted after this test.

You should see no new immediate technical-failure alerts from these two executions.

Seeing duplicate rows or alerts?

  • Confirm both failure events build fingerprint from the same three normalized fields in the same order.
  • Confirm the Row Upsert matching condition uses fingerprint.
  • Confirm the immediate Discord alert node is disconnected from the active handler path.

Help me diagnose why my duplicate failures did not collapse into one unsent row.

That is the alert-spam problem contained: repeated faults now become one durable retryable record. Next, you will group unsent records into a compact Discord digest.

Deliver a Retry-Safe Digest

Your error handler now collapses repeated technical failures into one unsent Data Table row. That durable record prevents alert spam.

Those rows remain invisible until a scheduled n8n workflow groups them into one Discord digest.

Delivery must succeed before the workflow changes row state. A failed send then leaves every failure fingerprint ready for retry.

In this step, get ready to:
  • Create a scheduled workflow that selects at most five unsent failures.
  • Format the selected failures into one compact Discord message.
  • Gate sent-state updates behind successful digest delivery.
Select and format one digest batch

A bounded batch keeps each digest readable. The workflow selects up to five unsent rows before formatting one message.

  • Return to the Personal project in n8n.
  • Create a workflow from the project workflow view.
  • Name the workflow Archive Failure Digest.

The new workflow canvas gives the digest its own execution path without changing the archive workflow.

  • Add a Schedule Trigger node from the workflow canvas.
  • Set the trigger interval to Minutes.
  • Enter 15 in Minutes Between Triggers.
  • Execute the Schedule Trigger once from the canvas.

You should see one trigger item in the node output. This confirms the workflow can begin a digest run.

  • Add a Data Table node from the Schedule Trigger output.
  • Set the Data Table operation to Row Get.
  • Select Archive Failure Log as the table.
  • Execute the Data Table node once.

You should see the existing controlled-failure row in the node output.

  • Add a condition where sent equals false.
  • Execute the Data Table node again.

You should now see only failure rows that still need delivery.

  • Disable Return All.
  • Set Limit to 5.
  • Execute the Data Table node once more.

The output should contain no more than five unsent failure rows.

A JavaScript Code node turns those rows into one item. That item carries both the digest text and the exact fingerprints eligible for an update.

  • Add a JavaScript Code node from the Data Table output.
  • Name the node Build Digest.

The canvas should now show Build Digest directly after the Data Table read.

  • Keep Run Once for All Items selected.
  • Replace the Code node editor contents with this formatter:
const failures = $input.all().slice(0, 5).map((item) => item.json);

if (failures.length === 0) {
  return [];
}

const shorten = (value, maximumLength) =>
  String(value ?? '').slice(0, maximumLength);

const fingerprints = failures.map((failure) => failure.fingerprint);

const lines = failures.map((failure, index) => [
  `${index + 1}. ${shorten(failure.workflowName, 40)} | ${shorten(failure.lastNode, 40)}`,
  shorten(failure.errorMessage, 150),
  shorten(failure.executionUrl, 100),
].join('\n'));

return [
  {
    json: {
      fingerprints,
      digestMessage: `Archive automation failure digest (${failures.length})\n\n${lines.join('\n\n')}`,
    },
  },
];

What does this code do?

  • The $input.all() call collects the rows supplied by the Data Table node.
  • The .slice(0, 5) expression caps the batch at five failures.
  • The shorten helper trims long values before they reach the message.
  • The fingerprints array preserves the exact records selected for this delivery.
  • The digestMessage field combines the selected failures into one compact message.

The length caps keep the five-row digest under Discord's 2000-character message-content limit.

  • Save Archive Failure Digest.
  • Execute Build Digest from the node editor.

You should see one output item containing a fingerprints array and a digestMessage value.

Build Digest returned no items?

Confirm that Archive Failure Log still contains a row where sent is false. Check that the Data Table node supplies that row to Build Digest.

Help me troubleshoot an empty Build Digest result.

✔️ Awesome, I've got everything!

Great. Save the workflow before you build the delivery gate.

ⓧ I'd like to double check the full code

const failures = $input.all().slice(0, 5).map((item) => item.json);

if (failures.length === 0) {
  return [];
}

const shorten = (value, maximumLength) =>
  String(value ?? '').slice(0, maximumLength);

const fingerprints = failures.map((failure) => failure.fingerprint);

const lines = failures.map((failure, index) => [
  `${index + 1}. ${shorten(failure.workflowName, 40)} | ${shorten(failure.lastNode, 40)}`,
  shorten(failure.errorMessage, 150),
  shorten(failure.executionUrl, 100),
].join('\n'));

return [
  {
    json: {
      fingerprints,
      digestMessage: `Archive automation failure digest (${failures.length})\n\n${lines.join('\n\n')}`,
    },
  },
];
Gate state updates behind delivery

Retry safety comes from ordering. A Merge node waits for the preserved fingerprints and the successful delivery branch.

Downstream updates have no path forward when Discord delivery stops the workflow. The selected rows therefore remain unsent after a failed delivery.

  • Add a Merge node to the workflow canvas.
  • Connect Build Digest directly to Input 1 on Merge.

The direct branch now preserves the original fingerprints array for the later update.

  • Add a Discord node from a second Build Digest branch.
  • Set the Discord operation to Message Send.
  • Select the existing Discord Webhook credential from earlier.

The delivery branch now uses the same credential-backed webhook without exposing its URL in the workflow.

  • Map the current item's digestMessage field into the Discord message content.
  • Set On Error to Stop Workflow.
  • Connect the Discord output to Input 2 on Merge.
  • Set Merge to Combine by Position.

Why does Merge protect retries?

Merge waits until both connected streams provide data. The direct stream carries the fingerprints while the second stream proves Discord accepted the message.

A delivery failure stops the workflow before Merge receives both inputs. No row can reach the sent-state update in that execution.

  • Add a Split Out node after Merge.
  • Set its list field to fingerprints.

Split Out converts the preserved array into one item per delivered fingerprint.

  • Add a Data Table node from the Split Out output.
  • Set the Data Table operation to Row Update.
  • Select Archive Failure Log as the table.

The update node now targets the same failure table that supplied the digest batch.

  • Set the update condition so fingerprint equals the current value emitted by Split Out.
  • Map only the sent field to true.
  • Save Archive Failure Digest.
Publish and verify the digest

Before you execute the workflow, ask yourself which records will change after the Discord message arrives.

  • Execute Archive Failure Digest manually once from the workflow canvas.

You should see the connected nodes complete through the final Data Table update. Discord should receive one compact failure digest.

  • Return to Discord from earlier.
  • Confirm that the channel contains one new archive automation failure digest.
  • Return to the completed digest execution in n8n.
  • Select Build Digest in the execution view.
  • Inspect the fingerprints array in its output.

That array is the exact delivery batch carried through the successful Discord branch.

  • Return to the Personal project's Data tables tab from earlier.
  • Open Archive Failure Log.
  • Compare its rows with the fingerprints array from the execution.
  • Confirm that every included fingerprint now has sent set to true.
  • Confirm that any row outside the five-row batch remains unsent.
  • Return to the Archive Failure Digest canvas.
  • Publish the workflow.
  • Confirm that the workflow shows its published state.

The schedule now runs every 15 minutes from the publication time. Only fingerprints carried through a successful delivery can advance to the sent state.

Digest delivered but rows stayed unsent?

Inspect Merge Input 1 for the fingerprints array. Confirm that Split Out produced one item for each value.

Check that the final Data Table node matches on fingerprint and updates only sent.

Help me trace the retry-safe digest update path.

That delivery guarantee is now locked in. Your published digest turns durable failure rows into one scheduled alert without sacrificing retries.

Secret mission

Prove Failed Deliveries Stay Retryable

A digest is only retry-safe if a failed delivery leaves its rows untouched. Force the Discord branch to fail. Recover it with a successful retry. Prove the exact records advance only after delivery.

Clean Up Your Resources

Clean Up Your Resources

These hardening resources add no new paid service because they run inside your existing local n8n lab. Choose whether to keep them active, pause the lab, or remove the new resources.

Resources you used:

  • Header authentication credential named Archive Webhook Header.
  • Reusable error workflow named Archive Automation Error Handler.
  • Data Table named Archive Failure Log.
  • Published digest workflow named Archive Failure Digest.
  • Hardening changes in the existing published archive workflow.

Keep everything running

No action needed. Choose this if you want authenticated archive requests plus scheduled failure reporting to remain available.

  • Leave the existing archive workflow published.
  • Keep Archive Automation Error Handler available for technical failures.
  • Retain Archive Failure Log for deduplicated failure records.
  • Leave Archive Failure Digest published for scheduled delivery.
  • Retain Archive Webhook Header for authenticated production requests.
  • Keep the existing Discord Webhook credential configured for digest delivery.
  • Leave the retained Compose project running in Docker Desktop.

The archive webhook remains protected. Failure digests continue to run every 15 minutes from the workflow's publication time.

Pause - I'll come back to this later

Pause the published entry points to stop archive requests plus scheduled digest runs. Your workflows, credentials, table rows, and Compose volume remain available for your return.

  • Return to Archive Failure Digest from the Personal project's workflow list.
  • Unpublish Archive Failure Digest from the workflow header.
  • Switch back to the existing archive workflow.
  • Unpublish the existing archive workflow from the workflow header.

The schedule stops running. The production webhook stops accepting archive jobs.

  • Switch back to Docker Desktop.
  • Stop the retained n8n Compose project with its project-level stop control.
  • Keep the Compose volume in place.

The retained volume preserves your workflows. It also preserves your credentials plus Data Table rows.

Delete - I don't want to use this again

Deletion permanently removes the stored failure history plus the shared header secret from n8n. Your existing processor, network, and Discord credential stay available for later projects.

The archive workflow must return to its pre-project version before you remove the resources referenced by its hardening changes.

  • Return to the existing archive workflow.
  • Open its version history from the workflow menu.
  • Select the version saved immediately before this project.
  • Restore the selected version.
  • Publish the restored archive workflow.

The archive workflow now uses its pre-project routes. The controlled failure branch plus error workflow connection are removed.

The scheduled digest can now be removed without leaving the archive workflow dependent on it.

  • Return to the Personal project's workflow list.
  • Open Archive Failure Digest.
  • Unpublish Archive Failure Digest from the workflow header.
  • Return to the Personal project's workflow list.
  • Open the workflow menu for Archive Failure Digest.
  • Select Delete.
  • Approve the deletion prompt.

The 15-minute digest schedule is now removed.

The reusable error handler is no longer connected to the restored archive workflow.

  • Open the workflow menu for Archive Automation Error Handler.
  • Select Delete.
  • Approve the deletion prompt.

The error workflow is now removed. Its stored failure records remain in the table until you delete them.

  • Switch back to the Personal project's Data tables tab.
  • Open the table menu for Archive Failure Log.
  • Select Delete.
  • Approve the deletion prompt.

The deduplicated failure rows are now removed.

  • Return to the credential list in your local n8n instance.
  • Open the credential menu for Archive Webhook Header.
  • Select Delete.
  • Approve the deletion prompt.

The shared production webhook secret is now removed from n8n.

  • Confirm the workflow list no longer contains Archive Failure Digest.
  • Confirm the workflow list no longer contains Archive Automation Error Handler.
  • Confirm the Data tables tab no longer contains Archive Failure Log.
  • Confirm the credential list no longer contains Archive Webhook Header.
  • Confirm the restored archive workflow no longer contains this project's hardening changes.

Cleanup is complete. Your existing archive-processor container plus archive-automation network remain available for later projects.

Nice Work!

Nice Work!

Outstanding work! You transformed your existing n8n archive pipeline into a secured automation with durable failure reporting. Its digest now updates failure state only after the Discord message succeeds.

You've learned how to:

  • Protected the production webhook with credential-backed Header authentication. Your Windows PowerShell sender now prompts for the shared secret without saving it.
  • Separated technical execution failures from successful non-ready business responses. Your reusable error workflow records controlled failures for inspection.
  • Replaced duplicate alerts with fingerprint-based Data Table upserts. Your published 15-minute failure digest sends up to five unsent failures in one message. It marks only delivered fingerprints as sent.
  • Secret Mission: Forced digest delivery to fail. You proved selected rows stay retryable until a successful delivery advances their sent state.

This completes Project 5 in your archive automation sequence. Your local lab now has the failure-handling foundation needed for future archive features.

Ready to quiz yourself?