Stripe webhook · server log
Missing raw body / body already used
TypeError: Body is unusable: Body has already been read · Webhook payload must be provided as a string or a BufferWhat it means
The request body stream can be read once. If something read it already, or you pass an object instead of the raw string, verification can't run. The Pages Router bodyParser: false config does nothing in App Router route handlers.
Common causes
- Reading req.json() for logging, then req.text() for verification
- Copying a Pages Router example (export const config = { api: { bodyParser: false } }, micro's buffer())
- Passing a parsed object to constructEvent
How to fix it
- Read once: const body = await req.text()
- Delete Pages Router body config and the micro dependency from App Router routes
- If you need to log, log after verification using the event object
// src/app/api/stripe/webhook/route.ts
import Stripe from "stripe";
export const runtime = "nodejs";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const sig = req.headers.get("stripe-signature");
if (!sig) return new Response("Missing signature", { status: 400 });
const body = await req.text(); // raw body: never req.json()
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
} catch (err) {
return new Response(`Invalid signature: ${(err as Error).message}`, { status: 400 });
}
// ...handle event.type...
return Response.json({ received: true });
}stripe listen --forward-to localhost:3000/api/stripe/webhook
# put the whsec_... it prints in .env.local, then restart npm run dev
stripe trigger checkout.session.completed
pass if stripe listen prints [200] for every forwarded event, not 400 or 500.
Prompt for Cursor or Claude Code
My Stripe webhook can't get the raw body. Rewrite src/app/api/stripe/webhook/route.ts for the App Router: read the body once with await req.text(), verify with constructEvent, remove any Pages Router bodyParser config or micro buffer() code, and don't read the body anywhere else.Not quite your error? Paste yours into the free VibeBoot Doctor or browse the Stripe webhook fixer.
next: skip the next one
Skip the debugging. The VibeBoot SaaS Starter ships with this already handled: a signature-verified webhook (raw body + constructEvent) that re-fetches the subscription from Stripe before saving it, with Vitest tests. Plus auth and a database on Next.js 16.4.3. $49, one-time.
14-day money-back guarantee · lifetime updates
Other Stripe webhook errors
$ fixed it? get the next one first
New fixes for what AI agents break, by email.
When we add a fix or a Cursor rule for a new Next.js, Auth.js, Prisma or Stripe break, it goes out in the VibeBoot newsletter. Free, occasional, unsubscribe in one click.