{"record":{"id":"604f305a537a8e29","repo":"n8n-io/n8n","slug":"webhook-request-failed-response-status-respo","errorCode":null,"errorMessage":"Webhook request failed: ${response.status} ${response.statusText}","messagePattern":"Webhook request failed: (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/ai-workflow-builder.ee/evaluations/cli/webhook.ts","lineNumber":259,"sourceCode":"\t\tlogger.info('Webhook request will be signed with HMAC-SHA256');\n\t} else {\n\t\tlogger.warn(\n\t\t\t'No webhook secret provided - request will not be signed. ' +\n\t\t\t\t'Consider using --webhook-secret for production use.',\n\t\t);\n\t}\n\n\t// Log masked URL to avoid exposing potential tokens in path/query\n\tlogger.info(`Sending results to webhook: ${maskWebhookUrl(webhookUrl)}`);\n\n\tconst response = await fetch(webhookUrl, {\n\t\tmethod: 'POST',\n\t\theaders,\n\t\tbody,\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Webhook request failed: ${response.status} ${response.statusText}`);\n\t}\n\n\tlogger.info(`Webhook notification sent successfully (status: ${response.status})`);\n}\n","sourceCodeStart":241,"sourceCodeEnd":264,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/ai-workflow-builder.ee/evaluations/cli/webhook.ts#L241-L264","documentation":"The webhook delivery `fetch` returned a non-2xx HTTP status; the thrown message includes `response.status` and `response.statusText`. Anything from the receiver — auth failure, payload rejected, server error — surfaces here. The URL is masked in logs just above the throw, so secrets in the path/query are not leaked. Note this only covers HTTP-level failures; network errors throw from `fetch` itself and are not wrapped.","triggerScenarios":"`fetch(webhookUrl, {method:'POST',...})` resolves but `response.ok` is false. Concretely: 401/403 (missing or wrong `--webhook-secret`), 404 (wrong URL/path), 422 (schema mismatch in `WebhookPayload`), 5xx (receiver down).","commonSituations":"Receiver expects a different signature scheme than HMAC-SHA256; the receiver's payload schema changed but the eval still sends the old shape; the URL drifted; rate limiting returns 429; an authenticated proxy in front of the receiver rejects the unsigned request.","solutions":["Match the status code to the cause: 401/403 → fix `--webhook-secret` / signature header name; 404 → fix URL; 4xx body → align payload schema; 5xx → check receiver health.","Verify the receiver logs the incoming `X-Webhook-Signature` / `X-Webhook-Timestamp` headers and validates them with the same HMAC scheme `generateWebhookSignature` uses (`sha256=<hex>`).","Reproduce with curl using the masked URL plus the same body to confirm whether the issue is the client or the receiver."],"exampleFix":"// before\n// receiver returns 401 because it expects a different header\nconst response = await fetch(webhookUrl, {method:'POST', headers, body});\nif (!response.ok) throw new Error(`Webhook request failed: ${response.status} ${response.statusText}`);\n// after\n// align header names with receiver (e.g. X-Hub-Signature-256) and re-sign\nheaders['X-Hub-Signature-256'] = generateWebhookSignature(signaturePayload, webhookSecret);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await sendWebhookResult({ webhookUrl, webhookSecret, payload, logger });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Webhook request failed:')) {\n    const status = e.message;\n    if (status.includes('401') || status.includes('403')) {\n      logger.error('webhook auth failed — check --webhook-secret and receiver signature scheme');\n    } else if (status.startsWith('Webhook request failed: 5')) {\n      // receiver-side fault: bounded retry with backoff is reasonable\n      await backoffRetry(() => sendWebhookResult({ webhookUrl, webhookSecret, payload, logger }), { tries: 3 });\n    } else {\n      logger.error(`webhook delivery failed: ${status}`);\n    }\n    return; // do not fail the whole eval run on a webhook error\n  }\n  throw e;\n}","preventionTips":["Decouple webhook delivery from eval success: catch delivery errors so a flaky receiver does not waste a completed run.","Document the exact signature scheme (header names, `sha256=<hex>` format) the receiver expects so secrets align.","Add an integration test that posts to a throwaway receiver to catch schema/signature drift early."],"tags":["webhook","network","http","delivery"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}