calcom/cal.diy · warning · HttpCode

Bad Request

Error message

Bad Request

What it means

Thrown when webhookHeadersSchema.safeParse(headers) fails - the request is missing one or more of the required Svix headers 'svix-id', 'svix-timestamp', 'svix-signature' used to authenticate webhook delivery. The parse error is console.error'd before the throw.

Source

Thrown at packages/app-store/alby/api/webhook.ts:33

  api: {
    bodyParser: false,
  },
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    if (req.method !== "POST") {
      throw new HttpCode({ statusCode: 405, message: "Method Not Allowed" });
    }

    const bodyRaw = await getRawBody(req);
    const headers = req.headers;
    const bodyAsString = bodyRaw.toString();

    const parseHeaders = webhookHeadersSchema.safeParse(headers);
    if (!parseHeaders.success) {
      console.error(parseHeaders.error);
      throw new HttpCode({ statusCode: 400, message: "Bad Request" });
    }

    const { data: parsedHeaders } = parseHeaders;

    const parse = eventSchema.safeParse(JSON.parse(bodyAsString));
    if (!parse.success) {
      console.error(parse.error);
      throw new HttpCode({ statusCode: 400, message: "Bad Request" });
    }

    const { data: parsedPayload } = parse;

    if (parsedPayload.metadata?.payer_data?.appId !== "cal.com") {
      throw new HttpCode({ statusCode: 204, message: "Payment not for cal.com" });
    }

    const payment = await prisma.payment.findFirst({
      where: {

View on GitHub (pinned to 176037d0af)

Solutions

  1. Ensure requests come from Svix/Alby carrying all three svix-* headers.
  2. Check that no proxy/CDN strips svix-id, svix-timestamp, or svix-signature.
  3. Use 'svix listen' (Svix CLI) for local testing so headers are populated correctly.
Defensive patterns

Strategy: validation

Validate before calling

const required = ['svix-id', 'svix-timestamp', 'svix-signature'];
const missing = required.filter((h) => !req.headers[h]);
if (missing.length) {
  // reject early with a clearer message than 'Bad Request'
}

Type guard

const hasSvixHeaders = (h: Record<string, unknown>): h is Record<string, string> =>
  typeof h['svix-id'] === 'string' &&
  typeof h['svix-timestamp'] === 'string' &&
  typeof h['svix-signature'] === 'string';

Prevention

When it happens

Trigger: A request to the webhook not originating from Svix (curl without svix headers); a proxy/load-balancer stripping custom headers; Svix relay misconfiguration; a replay tool omitting headers.

Common situations: Local testing without the Svix CLI; corporate proxy filtering svix-* headers; Alby webhook endpoint pointed at a URL behind a CDN that drops custom headers.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/43b020068ec472e3. Report an issue: GitHub.