hcengineering/platform · error
Invalid body
Error message
Invalid body
What it means
handleStripeWebhook returns HTTP 400 'Invalid body' when req.body is not a non-empty Buffer. Stripe signature verification (stripe.webhooks.constructEvent) requires the exact raw bytes, so the route expects express.raw() middleware output.
Source
Thrown at services/payment/pod-payment/src/providers/stripe/webhook.ts:45
* Documentation: https://stripe.com/docs/webhooks
*/
export async function handleStripeWebhook (
ctx: MeasureContext,
accountsUrl: string,
serviceToken: string,
webhookSecret: string,
stripeApiKey: string,
req: Request,
res: Response
): Promise<void> {
try {
// Body is a Buffer from express.raw() middleware
const rawBody = req.body as Buffer
const sig = req.headers['stripe-signature'] as string
if (!(rawBody instanceof Buffer) || rawBody.length === 0) {
ctx.error('Invalid webhook body')
res.status(400).json({ error: 'Invalid body' })
return
}
if (sig === undefined) {
ctx.error('Missing Stripe signature header')
res.status(400).json({ error: 'Missing signature' })
return
}
// Create Stripe instance for webhook verification
const stripe = new Stripe(stripeApiKey, { apiVersion: '2025-02-24.acacia' })
// Verify webhook signature and parse event
let event: Stripe.Event
try {
event = stripe.webhooks.constructEvent(rawBody, sig, webhookSecret)
} catch (err: any) {
ctx.error('Invalid Stripe webhook signature', { err })View on GitHub (pinned to 63e28dc964)
Solutions
- Register express.raw({ type: 'application/json' }) on the Stripe webhook route before the handler
- POST a non-empty raw JSON payload with Content-Type application/json
- Disable/reorder any global JSON body parser for this route so the raw body survives
- Check intermediary proxies for body mutation
Example fix
// before
app.post('/webhooks/stripe', handleStripeWebhook)
// after
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), handleStripeWebhook) Defensive patterns
Strategy: validation
Validate before calling
const rawBody = req.body as Buffer
if (!(rawBody instanceof Buffer) || rawBody.length === 0) {
throw new Error('Stripe webhook route requires express.raw() and a non-empty body')
} Type guard
function isRawBody(body: unknown): body is Buffer {
return body instanceof Buffer && body.length > 0
} Prevention
- Mount express.raw({ type: 'application/json' }) before the Stripe webhook handler
- Exclude webhook paths from global JSON body parsing
- Send raw payloads in tests, not parsed objects
- Confirm gateways don't rewrite request bodies
When it happens
Trigger: express.raw() middleware missing on the route so req.body is a parsed JS object; empty POST body; a body-transforming proxy; client sends no payload (e.g. GET-like health probe hitting the webhook URL).
Common situations: Framework default JSON body parser runs before the raw middleware; tests sending parsed objects; gateways like Cloudflare Workers re-serializing bodies.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/dd49bbd61467fd5d.
Report an issue: GitHub.