This error means stripe.webhooks.constructEvent() got a Stripe-Signature header value it could not parse at all — not "signature didn't match" (that's a different error), but "there was nothing usable in that header to check". In practice it's almost always one of these:
1. The header value you passed is undefined or empty
By far the most common cause. Node.js lowercases all incoming header names. If your code does:
const sig = req.headers['Stripe-Signature']; // undefined — wrong case
stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
req.headers['Stripe-Signature'] is undefined because Express/Node stores it as req.headers['stripe-signature']. Passing undefined (or an accidentally stringified "undefined") to constructEvent throws exactly this error, not a clearer "header missing" message.
Fix:
const sig = req.headers['stripe-signature']; // lowercase
const event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
2. The web server strips the header before your app sees it
Some PHP setups under Apache/FastCGI don't populate $_SERVER['HTTP_STRIPE_SIGNATURE'] unless the server is configured to pass through non-standard headers, and some reverse proxies / API gateways only forward an explicit allow-list of headers. If var_dump($_SERVER['HTTP_STRIPE_SIGNATURE']) (or logging req.headers in Node) shows the key is missing entirely — not just the value being odd — the header is being dropped upstream of your code, not in it.
Fix: check your proxy/gateway/hosting config for a header allow-list and explicitly permit Stripe-Signature, or log all incoming header names to confirm it arrives.
3. You're reading the header from the wrong object in a serverless handler
On some serverless platforms the raw request is wrapped (API Gateway event.headers, a framework-specific request object). Header keys can appear with mixed case (Stripe-Signature) or lowercase depending on the platform version. Log Object.keys(event.headers) once during setup rather than guessing the casing.
4. Manually constructing the header string
If you're testing with curl or a custom client and typing the signature header by hand instead of using the real one Stripe sent, the format (t=...,v1=...) has to be exact — a stray space or missing comma also produces this error. Use the Stripe CLI (stripe listen --forward-to ...) for real test deliveries instead of hand-crafting the header.
Check first: log typeof sig and sig right before the constructEvent call. If it prints undefined, it's #1. If the header key isn't in the request at all, it's #2 or #3.
If you've checked all of this and it's still failing, or you want someone to look at your actual handler instead of a generic checklist, I do a $39 done-for-you audit of a Stripe integration: https://buy.stripe.com/fZufZgaxfaye0LN4hi7IY07
Top comments (0)