The Webhook Timeout Trap: Why My n8n Webhook Stopped Timing Out (Respond First, Work Later)

# automation# ai# webdev# programming
The Webhook Timeout Trap: Why My n8n Webhook Stopped Timing Out (Respond First, Work Later)HaoPeng Zhang

The Webhook Timeout Trap This is part of my build-in-public series on running LLM...

The Webhook Timeout Trap

This is part of my build-in-public series on running LLM workflows in n8n in production. Everything here is from a real template I sell and support — the mistakes are mine, the fixes are tested.

The duplicate orders nobody ordered

Three weeks ago I got a ping I never want to see: "Hey, we received the same order notification three times."

It was my own order-processing webhook. A store sends an order event → my n8n webhook receives it → the workflow validates the order, calls an LLM to generate a fulfillment summary, writes rows to my database, sends confirmation emails. About 60–90 seconds of real work, end to end.

The problem: the sender had a 30-second timeout. My workflow took 90 seconds to answer. So the sender did exactly what senders do — it retried. Twice. Three "successfully processed" runs, three confirmation emails, three database rows for the same order.

My sweeper pattern (I wrote about it in this series) made every step idempotent, so nothing double-charged anyone. But the sender kept seeing failures. Their dashboard was red. My workflow's executions were green. Green runs, angry partner. That's the trap.

Why the trap exists

In n8n's default setup, a Webhook node collects the entire workflow's output and returns it as the HTTP response. That means the HTTP connection stays open for the whole workflow — every LLM call, every API wait, every database write.

n8n self-hosted closes idle webhook connections after about 120 seconds. Cloud has similar limits. But real-world senders are far less patient:

  • Stripe retries after its own timeout windows
  • Meta/TikTok verify-and-retry on webhook events
  • Many SaaS apps give up at 10–30 seconds and fire a duplicate

You don't control the sender's timeout. You only control how fast you answer. I was designing my workflow to finish fast. What I actually needed was to answer fast.

The fix: respond first, work later

The change took about ten minutes. The idea is one sentence: the webhook's only job is to acknowledge receipt; the real work happens after the response.

In n8n, you can do this two ways:

Option A — Webhook node set to respond "When Received" (or immediately). The workflow keeps running after responding. Newer n8n versions let you pick the response mode on the node itself.

Option B — a "Respond to Webhook" node placed right after the trigger. I use this one because it's explicit. My flow now looks like:

Webhook Trigger
  → Respond to Webhook (200, {"received": true, "event_id": "{{ $json.id }}"})
  → Dedupe check (have I seen this event_id? skip if yes)
  → ... all the slow LLM/database/email work ...
Enter fullscreen mode Exit fullscreen mode

The response goes out in under a second. The sender is happy. The workflow continues asynchronously in the background.

My webhook response p95 went from ~70 seconds to ~400 milliseconds. Sender retries dropped to zero — because from the sender's perspective, there was never a failure to retry.

The two things you must not skip

Responding fast is only half the fix. It creates two obligations:

1. Idempotency is now mandatory, not optional. When you respond before doing the work, you can never distinguish "sender retried because it timed out" from "sender sent the same event twice." Use the sender's event ID as your dedupe key and check it before doing anything. I wrote up my dedupe/sweeper pattern in the series — the core idea is: if the event_id already exists in your processed-events table, skip everything and return the stored result.

2. You need to know when background work fails. With the respond-first pattern, the sender will never tell you something went wrong — you told them everything was fine. So the tail of the workflow needs its own error reporting: an Error Trigger workflow that pings me (email + a Slack message) with the event_id and the failed node. This is the same "quiet fail" monitoring I wrote about last week — green HTTP responses don't mean green outcomes.

Both halves together: fast acknowledgment + dedupe on event_id + independent error reporting. Miss any one and you've just moved the failure somewhere harder to see.

The checklist I run now for every new webhook

Before I ship any webhook receiver in n8n:

  1. Response goes out in < 1 second (Respond to Webhook right after the trigger)
  2. Dedupe on the sender's event_id before any side effect
  3. Error Trigger workflow wired to the real workflow, reporting to me directly
  4. A reconciliation query that lists "received but not completed" events (my sweeper catches these)
  5. The response body includes the event_id, so the sender and I can correlate

It's boring. It works. Senders stopped retrying, and my execution history stopped lying to partners.


I'm building AI Automation Lab — production-ready n8n workflow templates. The free AI Hook Generator shows how I structure real workflows; my open-source templates live at github.com/zhp910318/n8n-ai-automation-lab.