remotion-dev/remotion · error · Error
Signatures do not match
Error message
Signatures do not match
What it means
Thrown by validateWebhookSignature() when the incoming signatureHeader does not equal the HMAC computed over the body and the shared secret. A mismatch means the request was not authentic, was tampered with, or used a different secret.
Source
Thrown at packages/lambda-client/src/validate-webhook-signature.ts:40
"No 'body' was provided to validateWebhookSignature().",
);
}
if (typeof require === 'undefined') {
throw new Error('validateWebhookSignature can only be called from Node.JS');
}
const Crypto = require('crypto');
const hmac = Crypto.createHmac('sha512', secret);
const signature = `sha512=${hmac.update(JSON.stringify(body)).digest('hex')}`;
if (!signatureHeader || signatureHeader === 'NO_SECRET_PROVIDED') {
throw new Error('No webhook signature was provided');
}
if (signatureHeader !== signature) {
throw new Error('Signatures do not match');
}
};
View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Capture and HMAC the RAW request body (the exact bytes Remotion signed), not a re-serialized object — use express.json({verify}) or a raw-body middleware.
- Confirm the secret string matches byte-for-byte what was passed to renderMediaOnLambda() (no trailing newline, same encoding).
- Reject the request with 401 on signature mismatch and log nothing sensitive.
Example fix
// before (re-serialized body, drifts from signed bytes)
app.post('/webhook', express.json(), (req, res) => {
validateWebhookSignature({secret, body: req.body, signatureHeader: req.headers['x-remotion-signature']});
});
// after (capture raw body)
app.post('/webhook', express.json({verify: (req, _res, buf) => { req.rawBody = buf; }}), (req, res) => {
validateWebhookSignature({secret, body: JSON.parse(req.rawBody), signatureHeader: req.headers['x-remotion-signature']});
}); Defensive patterns
Strategy: try-catch
Validate before calling
// Capture the RAW request body — the exact bytes Remotion signed.
app.post('/webhook', express.json({verify: (req, _res, buf) => { req.rawBody = buf; }}), (req, res) => {
try {
validateWebhookSignature({secret, body: JSON.parse(req.rawBody), signatureHeader: req.headers['x-remotion-signature']});
res.status(200).send('ok');
} catch {
res.status(401).send('unauthorized');
}
}); Try / catch
try {
validateWebhookSignature({secret, body, signatureHeader});
} catch (err) {
// Do NOT distinguish 'Signatures do not match' from other failures in the response.
return res.status(401).send('unauthorized');
} Prevention
- Verify the RAW body, not a re-serialized object — use express.json({verify}) or a raw-body middleware.
- Make sure the secret on the validator side matches the one passed to renderMediaOnLambda().
- Return a generic 401 on any failure; never reveal which signature check failed.
When it happens
Trigger: The body the receiver parsed differs from the raw body Remotion signed (most common), the secret on the receiver differs from the one passed to renderMediaOnLambda(), or the request was replayed/tampered.
Common situations: Express re-serializing req.body with different key order / whitespace than the raw JSON Remotion used to compute the HMAC; a typo in the secret; checking the header before body-parser has run; an attacker actually tampering.
Related errors
- No 'secret' was provided to validateWebhookSignature().
- No 'body' was provided to validateWebhookSignature().
- No webhook signature was provided
- validateWebhookSignature can only be called from Node.JS
- Invalid public file path: ${path}
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/1882e284ebf3ca92.
Report an issue: GitHub.