{"record":{"id":"f63aca4143b8ca4b","repo":"twentyhq/twenty","slug":"raw-request-body-was-not-forwarded-by-the-server","errorCode":null,"errorMessage":"Raw request body was not forwarded by the server; cannot verify the webhook signature","messagePattern":"Raw request body was not forwarded by the server; cannot verify the webhook signature","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/twenty-apps/public/call-recorder/src/logic-functions/recall-webhook.ts","lineNumber":36,"sourceCode":"\n// A thrown error becomes a non-2xx, which makes Svix retry; a returned result dispatches to the target.\nexport const recallWebhookRouteHandler = (\n  routePayload: RoutePayload<RecallWebhookBody>,\n): RecallWebhookResolverResult => {\n  const webhookSecret = getApplicationVariableValue(\n    RECALL_WEBHOOK_SECRET_ENV_VAR_NAME,\n  );\n\n  if (!isNonEmptyString(webhookSecret)) {\n    throw new Error(\n      'RECALL_WEBHOOK_SECRET server variable is not set. A server admin must copy it from the Recall webhook endpoint settings and set it on the Call Recorder application registration.',\n    );\n  }\n\n  const { rawBody } = routePayload;\n\n  if (isUndefined(rawBody)) {\n    throw new Error(\n      'Raw request body was not forwarded by the server; cannot verify the webhook signature',\n    );\n  }\n\n  const signatureCheck = verifyRecallWebhookSignature({\n    rawBody,\n    headers: routePayload.headers,\n    secret: webhookSecret,\n  });\n\n  if (!signatureCheck.valid) {\n    throw new Error(`Invalid webhook signature: ${signatureCheck.error}`);\n  }\n\n  const body = routePayload.body;\n\n  if (isUndefined(body) || isNull(body)) {\n    throw new Error('Webhook payload was empty');","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/twentyhq/twenty/blob/1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6/packages/twenty-apps/public/call-recorder/src/logic-functions/recall-webhook.ts#L18-L54","documentation":"Webhook signature verification needs the exact raw bytes of the request body, so the route handler requires `routePayload.rawBody` (forwarded via `serverRouteTriggerSettings.forwardedRequestHeaders` and the platform's raw-body forwarding). If `rawBody` is undefined, the handler cannot compute the HMAC and throws. This is a platform/transport misconfiguration: the server is expected to forward the raw body but did not.","triggerScenarios":"The logic function platform/routing layer was changed to stop forwarding the raw body (e.g. only forwarding the parsed JSON body), the route trigger settings were edited to drop the raw-body forwarding, or a proxy in front re-encodes the body so the raw bytes are unavailable.","commonSituations":"A platform upgrade that changed how `RoutePayload.rawBody` is populated; misconfigured `serverRouteTriggerSettings`; a reverse proxy buffering/transforming the request body.","solutions":["Ensure the logic function's `serverRouteTriggerSettings` still enables raw-body forwarding (the route declares the svix/webhook headers; confirm the platform also forwards the raw body).","Check the platform version — if `rawBody` support regressed, roll forward to a version that populates `RoutePayload.rawBody`.","If a proxy is in the path, configure it to pass the request body through unmodified.","Until fixed, the route cannot securely verify signatures; do not disable verification as a workaround."],"exampleFix":"// before\nconst { rawBody } = routePayload;\nif (isUndefined(rawBody)) {\n  throw new Error('Raw request body was not forwarded by the server; cannot verify the webhook signature');\n}\n\n// after — log which payload fields arrived to aid platform debugging\nconst { rawBody } = routePayload;\nif (isUndefined(rawBody)) {\n  console.error('[recall-webhook] rawBody missing; headers=', Object.keys(routePayload.headers ?? {}), 'hasBody=', !isUndefined(routePayload.body));\n  throw new Error('Raw request body was not forwarded by the server; cannot verify the webhook signature');\n}","handlingStrategy":"validation","validationCode":"// In tests/platform checks, assert RoutePayload carries a rawBody before enabling the route.\nexport const routeSupportsRawBody = (payload: RoutePayload<unknown>): boolean =>\n  !isUndefined(payload.rawBody);","typeGuard":"const hasRawBody = (\n  p: RoutePayload<unknown>,\n): p is RoutePayload<unknown> & { rawBody: string | Buffer } =>\n  !isUndefined(p.rawBody);","tryCatchPattern":null,"preventionTips":["Keep `serverRouteTriggerSettings.forwardedRequestHeaders` in sync with what the platform actually forwards, including raw-body forwarding.","Add a platform regression test that asserts `RoutePayload.rawBody` is populated for webhook routes.","Do not disable signature verification as a workaround; fix the transport.","Log which payload fields arrived whenever rawBody is missing to speed platform debugging."],"tags":["webhook","recall","call-recorder","security","transport","configuration"],"backgroundTag":null,"analyzedSha":"1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6","analyzedAt":"2026-08-12T15:37:27.593Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}