← n8n Errors|Debugalo

n8n Error Reference

Webhook Bad Request (400)

A 400 Bad Request on an n8n webhook means either the incoming request was rejected before the workflow could process it, or a downstream node failed because the payload didn't match what it expected. The direction matters: inbound failures (a third-party service sending to n8n) and outbound failures (n8n calling an external webhook and getting 400 back) have completely different causes and fixes.

Quick Diagnosis

First confirm which direction failed. Inbound: open the execution log — if the Webhook node shows data in its Output tab, n8n received the payload and the failure is in a downstream node. No execution at all means the workflow is inactive or the wrong URL was used. Outbound: open the HTTP Request node's Output tab and read the response body — the external service's 400 message names the specific field or format problem.

Error variants

These are the exact strings that appear when an n8n webhook request is rejected — from n8n's own execution log, from HTTP Request node responses, or from execution failures caused by malformed inbound payloads:

Webhook call got a bad request
n8n's own error message when the Webhook node rejects an incoming request before the workflow runs. Most commonly caused by a payload size limit being exceeded, an authentication header mismatch on a webhook configured with Basic or Header auth, or a request method mismatch (the sender used GET on a POST-only webhook).
Request failed with status code 400
The Axios error surfaced by an HTTP Request node when n8n is calling an external webhook endpoint and that endpoint returns 400. The 400 is from the external service, not from n8n. Open the HTTP Request node, enable "Include Response Headers and Status" in Options, re-run, and read the response body — the external webhook's error message will name the specific problem.
ERROR: Workflow could not be started!
A request was sent to n8n's test webhook URL after the workflow was activated (or to the production URL while still in test mode). n8n's Webhook node has two separate URLs: a test URL that only works while the workflow is open in the editor and listening, and a production URL that only works while the workflow is active. Using the wrong URL for the context returns this error.
{"code":400,"message":"Required field 'event' is missing"}
The external webhook endpoint n8n is calling returned a 400 with a structured error body. The field name in the message — 'event' in this example — tells you exactly what the external service expected but didn't receive. Check the outbound payload n8n is sending against the webhook endpoint's documented required fields.
X-Hub-Signature-256 header is missing or signature does not match
GitHub, Stripe, and other services sign outbound webhook payloads with an HMAC signature. If the n8n Code node validating the signature computes a different hash — because the raw body was parsed before comparison, the wrong secret was used, or the body encoding changed — the validation fails and the workflow rejects the request. The raw body must be compared, not a re-serialized version.

What this error means

HTTP 400 means the server that received the request considered it malformed or invalid — not an auth failure (that's 401), not a missing resource (that's 404), but a problem with the request itself. In n8n, this surfaces in two ways: a third-party service sends a request to n8n's webhook URL that fails validation or triggers a downstream error, or n8n sends an outbound request to an external webhook that the remote server rejects. The payload shape, Content-Type header, request method, and signature headers are the most common points of failure in both directions.

Common causes

1

Inbound: payload missing fields the downstream nodes expect

The Webhook node receives the request successfully, but a downstream Code node, IF node, or Set/Edit Fields node references a field that isn't in the payload. The workflow execution fails, but n8n has already accepted the request — so the sender sees a 200, not a 400. The 400 in this case is a logical failure visible only in the execution log, not in the HTTP response to the sender.

2

Inbound: Content-Type missing or not application/json

n8n's Webhook node auto-parses the request body as JSON only when the sender includes Content-Type: application/json. Without it, the body arrives as a raw string in $json.body. A downstream node expecting $json.fieldName finds undefined instead. This is the most common cause of webhook failures from services that send form-encoded data (application/x-www-form-urlencoded) or plain text.

3

Test URL vs production URL mismatch

n8n generates two webhook URLs per Webhook node: a test URL (contains /webhook-test/ in the path) and a production URL (contains /webhook/). The test URL only works while the workflow editor is open and actively listening. The production URL only works while the workflow is activated. Sending to the wrong URL for the context produces an immediate error before any workflow logic runs.

4

Inbound: HMAC signature validation failing

When a service like GitHub or Stripe signs its webhook payloads, the n8n workflow must validate the signature in a Code node before processing. Validation fails when: the raw request body was JSON-parsed before hashing (re-serialization changes whitespace and key order), the wrong secret is referenced in the Code node, or the signature header name doesn't match what the Code node reads.

5

Outbound: n8n sending wrong Content-Type or missing required fields

An HTTP Request node calling an external webhook sends a payload that the remote server rejects. Common causes: the body is sent as application/x-www-form-urlencoded when the endpoint expects application/json, required fields are absent because an upstream node produced no data for them, or expression-built values produce null for fields the endpoint marks as required.

6

Outbound: query parameters sent in body, or vice versa

Some webhook endpoints expect certain values as URL query parameters and others in the request body. An HTTP Request node that puts everything in the body — or everything in query parameters — sends a structurally valid request that the endpoint still rejects as 400. Check the external webhook's documentation to confirm which fields go where.

How to diagnose it

  1. 1

    Check the n8n execution log first. If there is no execution entry for the failed request, the Webhook node rejected it before the workflow ran — check the webhook URL (test vs. production), the HTTP method, and any auth configuration on the node.

  2. 2

    If an execution exists, open it and click the Webhook node. Check the Output tab — confirm the payload n8n received looks correct. If fields are missing or the body is a raw string instead of a parsed object, the sender did not include Content-Type: application/json.

  3. 3

    If the Webhook node output looks correct but a downstream node failed, open the failing node and check its Input tab. Compare the field names in the actual data against the expression or code that references them — look for missing fields, wrong nesting, or unexpected field names from the third-party service.

  4. 4

    For signature validation failures: in the Code node, log the raw header value and your computed HMAC before comparing them — add console.log(receivedSig, computedSig). Re-run and check the execution log output. Confirm you are hashing the raw body bytes, not a re-parsed JSON string.

  5. 5

    For outbound 400 errors (n8n calling an external webhook): enable "Include Response Headers and Status" on the HTTP Request node, re-run, and read the full response body. The external service's error message almost always names the specific invalid or missing field.

  6. 6

    For test vs. production URL confusion: in the Webhook node, copy both URLs and confirm which one the external service has registered. The test URL contains /webhook-test/ and requires the editor to be open and listening. The production URL requires the workflow to be activated (toggle in the top-right of the workflow editor).

  7. 7

    If the payload shape from a third-party service is different from what you expected: use the Webhook node's test mode — click "Listen for test event" in the node, trigger a real event from the service, and inspect the exact payload structure in the Output tab before writing any downstream expressions.

n8n-specific scenarios

Inbound: GitHub webhook → HMAC signature validation failure

GitHub signs webhook payloads with HMAC-SHA256 using a secret you configure in the repository settings. n8n receives the payload and a Code node validates the signature. The most common failure: the Code node calls JSON.parse($input.first().json.body) and hashes the re-serialized string — but GitHub's signature was computed over the original raw bytes, which may have different whitespace. Fix: access the raw body via $input.first().json.body as-is (without re-parsing), compute HMAC-SHA256 with the crypto module, and compare with the X-Hub-Signature-256 header. If the secret in the Code node doesn't match the one set in GitHub's webhook settings, the comparison always fails regardless of body handling.

Inbound: Stripe webhook → test event hitting production workflow

Stripe sends test events (from the dashboard's "Send test webhook" button) using test-mode event IDs like evt_test_... to whatever URL is registered. If the production n8n workflow URL is registered in Stripe's test webhook settings but the workflow logic expects live-mode event shapes, or if a Code node validates the Stripe signature using the live-mode secret against a test-mode payload signed with the test secret, validation fails with a 400 or the execution errors. Maintain separate webhook URLs in n8n for test and production Stripe environments, each with its own credential and signing secret.

Inbound: Typeform or third-party service → payload structure not matching workflow

Typeform, Jotform, and similar services send webhook payloads with nested structures — form answers are often an array of objects with question IDs rather than flat key-value pairs. A Code node expecting $json.email fails when the actual path is $json.form_response.answers[2].email. Fix: use the Webhook node's "Listen for test event" mode, submit a real form entry, and inspect the full payload structure in the Output tab before writing any field references. Never assume the payload shape matches what the service documentation shows — test with live data.

Inbound: form-encoded body arriving as raw string

A service sends a webhook with Content-Type: application/x-www-form-urlencoded. n8n's Webhook node does not auto-parse form-encoded bodies the same way it parses JSON — the body may arrive in $json.body as a raw string like "field1=value1&field2=value2". Add a Code node immediately after the Webhook node to parse it: const params = new URLSearchParams($input.first().json.body); return [{ json: Object.fromEntries(params) }]. This produces a properly structured object for downstream nodes.

Outbound: HTTP Request node → external webhook rejecting expression-built body

An HTTP Request node constructs a JSON body using expressions: fields sourced from upstream nodes that returned no data produce null or undefined values. The external webhook endpoint marks those fields as required and returns 400. Fix: add an IF node before the HTTP Request node to confirm all required fields are populated, and use a Stop And Error node on the empty-field branch so the failure is visible in the execution log rather than silently producing a bad request.

Outbound: Respond to Webhook node returning 400 intentionally

The Respond to Webhook node can be configured to return any status code and body. If validation logic upstream routes to a Respond to Webhook node with status 400 and an error body, n8n is deliberately returning 400 to the original sender. This is correct behavior — but if it's firing unexpectedly, check the IF or Switch node that routes to it. Open the execution, find the branch that reached the Respond to Webhook node, and trace back to the condition that triggered it.

Paste your full error message and the failed node's output into Debugalo to get a structured breakdown: the exact failed step, root cause, and concrete fix steps.

Analyze this error →

FAQ

What's the difference between n8n's test webhook URL and production webhook URL?

The test URL (containing /webhook-test/ in the path) only works while the workflow editor is open and the Webhook node is actively listening — you click 'Listen for test event' and then trigger a request. It does not persist. The production URL (containing /webhook/) only works while the workflow is activated using the toggle in the top-right of the editor. Sending to the test URL when no one is listening, or to the production URL when the workflow is inactive, produces an immediate error before any workflow logic runs. Always confirm which URL is registered with the external service and whether the workflow state matches.

How do I validate a webhook signature (HMAC) in n8n?

Use a Code node immediately after the Webhook node. Access the raw body with $input.first().json.body and the signature header with $input.first().headers['x-hub-signature-256'] (or whichever header the service uses). Compute the HMAC with Node's built-in crypto module: const crypto = require('crypto'); const computed = 'sha256=' + crypto.createHmac('sha256', SECRET).update(rawBody).digest('hex');. Compare computed against the received header using crypto.timingSafeEqual() to prevent timing attacks. If validation fails, use a Respond to Webhook node to return 400 and stop the execution — do not process the payload.

The Webhook node shows data in the Output tab but the workflow still fails. Is that a Bad Request?

No. If the Webhook node has output data, n8n accepted the request — the sender received a 200 (or whatever the Webhook node is configured to return). The failure is a workflow execution error in a downstream node, not a 400. Open the failed execution, find the red node, and check its Input tab to see what data it received. The fix will be in the downstream node's expressions or logic, not in the webhook configuration.

How do I make n8n return a 400 response to the webhook sender?

Add a Respond to Webhook node to your workflow. Set the response code to 400 and the response body to a JSON object describing the error. Route to this node from an IF or Switch node when validation fails. Important: the Webhook node must have 'Respond' set to 'Using Respond to Webhook Node' in its settings — if it's set to 'Immediately,' n8n returns the response before the workflow finishes and the Respond to Webhook node has no effect.

How do I inspect the raw headers and body of a request n8n received?

In the Webhook node settings, enable 'Raw Body' if you need the unprocessed body bytes (required for HMAC signature validation). To see headers, add $input.first().headers to a Set/Edit Fields node or log them in a Code node with console.log(JSON.stringify($input.first().headers)). The headers object is available on every execution — the Output tab in the Webhook node shows the parsed body but not the headers by default.

Related Guides