Significant-Gravitas/AutoGPT · warning · HTTPException
Invalid payload
Error message
Invalid payload
What it means
Raised (400) by /credits/stripe_webhook when stripe.Webhook.construct_event raises ValueError, which the Stripe SDK uses for a malformed request body (payload is not valid JSON / cannot be parsed as an event). It fires before signature verification semantics matter — the body itself is unparseable.
Source
Thrown at autogpt_platform/backend/backend/api/features/v1.py:1437
if not webhook_secret:
# Guard: an empty secret allows HMAC forgery (attacker can compute a valid
# signature over the same empty key). Reject all webhook calls when unconfigured.
logger.error(
"stripe_webhook: STRIPE_WEBHOOK_SECRET is not configured — "
"rejecting request to prevent signature bypass"
)
raise HTTPException(status_code=503, detail="Webhook not configured")
# Get the raw request body
payload = await request.body()
# Get the signature header
sig_header = request.headers.get("stripe-signature")
try:
event = stripe.Webhook.construct_event(payload, sig_header, webhook_secret)
except ValueError:
# Invalid payload
raise HTTPException(status_code=400, detail="Invalid payload")
except stripe.SignatureVerificationError:
# Invalid signature
raise HTTPException(status_code=400, detail="Invalid signature")
# Defensive payload extraction. A malformed payload (missing/non-dict
# `data.object`, missing `id`) would otherwise raise KeyError/TypeError
# AFTER signature verification — which Stripe interprets as a delivery
# failure and retries forever, while spamming Sentry with no useful info.
# Acknowledge with 200 and a warning so Stripe stops retrying.
event_id = event.get("id", "")
event_type = event.get("type", "")
# Event-level dedup: short-circuit identical re-deliveries before any
# handler runs. Stripe retries the same event.id on non-2xx responses, and
# not every downstream handler is independently idempotent.
if not await _claim_stripe_event(event_id):
logger.info(
"stripe_webhook: event %s (%s) already processed; skipping",View on GitHub (pinned to 9c8bb5550f)
Solutions
- Confirm the caller is really Stripe: webhooks must be raw POSTs of Stripe event JSON with a stripe-signature header.
- Remove any middleware that buffers/re-encodes the request body; the handler needs the untouched raw bytes.
- Reproduce with `stripe trigger <event>` or the Stripe CLI to verify genuine deliveries pass.
Defensive patterns
Strategy: validation
Validate before calling
if (request.headers.get('content-type') !== 'application/json') reject(400); // only at your own edge; genuine Stripe deliveries are raw JSON POSTs Try / catch
Stripe retries 400s for up to ~3 days; a persistent 400 pattern means a proxy or non-Stripe caller is hitting the endpoint — fix the source, don't catch.
Prevention
- Keep /credits/stripe_webhook out of health-check/scanner paths; restrict it at the ingress to Stripe IP ranges if possible.
- Never wrap the handler with body-parsing middleware — construct_event needs the exact raw bytes.
- Verify webhook endpoint plumbing with `stripe trigger checkout.session.completed` after deploy.
When it happens
Trigger: Any non-Stripe client POSTing garbage (HTML error page, form-encoded data, truncated JSON) to /credits/stripe_webhook; a proxy or middleware that consumes and re-encodes the raw body incorrectly; curl tests without a proper JSON event body.
Common situations: Load balancer health probes hitting the webhook path; security scanners posting junk; middleware that reads request.body() before the handler and replaces it with a re-serialized object, breaking the exact bytes Stripe signed.
Related errors
- Invalid signature
- Webhook not configured
- Payment redirect URLs cannot be validated: frontend_base_url
- success_url and cancel_url must match the platform frontend
- Unable to start checkout right now. Please try again or cont
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/c168b88ac6a169ac.
Report an issue: GitHub.