🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 6 Min Lesezeit
0

Webhook 400 Bad Request: Debugging & Fixes

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




The 400 Bad Request Problem



A webhook 400 bad request error hits your logs at 2 AM. Your integration was working yesterday. The provider (Stripe, GitHub, Shopify) is sending data, but your handler is rejecting it with HTTP 400. You've checked the endpoint URL. You've verified the domain. But the webhook malformed request keeps coming back.



This is one of the most frustrating webhook integration failures because the error message is intentionally vague—HTTP 400 means "I couldn't parse or validate what you sent," but not why. The root cause could be anywhere: raw body parsing, header mismatches, JSON encoding, signature verification, or middleware order. This guide walks you through the exact debugging steps and fixes that work.






Prerequisites




  • A running backend service (Node.js, Python, Go, etc.) with a webhook handler already defined

  • Access to your webhook provider's documentation and request logs (Stripe Dashboard, GitHub Settings, etc.)

  • Basic familiarity with HTTP headers, JSON, and raw request bodies

  • A tool to inspect incoming webhook payloads (curl, Postman, or a local webhook inspector)

  • Understanding of your framework's middleware execution order (Express, Fastify, Django, Flask, etc.)






Debugging Webhook 400 Bad Request Errors: Step-by-Step






Step 1: Capture the Actual Request



The first rule: never debug blind. You need to see the exact bytes your handler received.




CODE
# If you're running locally, start a simple echo server to see raw requests
nc -l 3000






Or use a webhook inspector to capture the full request (headers, body, method):




CODE
npx @anonymilyhq/cli listen 3000






This command gives you a stable endpoint URL like https://api.anonymily.com/h/my-endpoint that captures all incoming webhooks and forwards them to your local handler. You'll see the exact payload, headers, and timestamps in the web dashboard—crucial for debugging.






Step 2: Check Content-Type and Raw Body Handling



The most common cause of webhook 400 errors is raw body parsing. Many providers (Stripe, GitHub, Twilio) require the raw, unparsed request body for signature verification. If your middleware parses JSON before you extract the raw body, the signature check fails.




CODE
// ❌ WRONG: JSON middleware runs first, raw body is lost
app.use(express.json());
app.post('/webhook', (req, res) => {
const signature = req.headers['x-signature'];
// req.body is parsed, but raw bytes are gone
const verified = verifySignature(req.body, signature); // FAILS
res.sendStatus(200);
});

// ✅ CORRECT: Capture raw body before JSON parsing
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-signature'];
const rawBody = req.body; // Still raw Buffer
const verified = verifySignature(rawBody, signature); // Works
const parsed = JSON.parse(rawBody);
res.sendStatus(200);
});









Step 3: Validate JSON Encoding



Some providers send Content-Type: application/json; charset=utf-8. Others send application/x-www-form-urlencoded with JSON nested inside. Check your provider's docs.




CODE
# Python example: handle both encodings
from flask import Flask, request
import json

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
content_type = request.headers.get('Content-Type', '')

if 'application/json' in content_type:
payload = request.get_json()
elif 'application/x-www-form-urlencoded' in content_type:
# Some providers send JSON in a form field
payload = json.loads(request.form.get('payload', '{}'))
else:
return 'Unsupported Content-Type', 400

if not payload:
return 'Empty or invalid JSON', 400

# Process payload
return '', 200









Step 4: Verify Signature Headers



Providers sign webhooks to prove authenticity. A missing or mismatched signature header causes 400 errors if your handler rejects unsigned requests.




CODE
// Stripe example: signature in X-Stripe-Signature header
const crypto = require('crypto');

function verifyStripeSignature(rawBody, signature, secret) {
const [timestamp, signedContent] = signature.split(',').map(s => s.split('=')[1]);
const computed = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody.toString()}`)
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(computed),
Buffer.from(signedContent)
);
}

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-stripe-signature'];
if (!signature) {
return res.status(400).json({ error: 'Missing signature header' });
}

try {
if (!verifyStripeSignature(req.body, signature, process.env.STRIPE_WEBHOOK_SECRET)) {
return res.status(400).json({ error: 'Invalid signature' });
}
} catch (err) {
return res.status(400).json({ error: 'Signature verification failed' });
}

res.json({ received: true });
});









Step 5: Check Endpoint Configuration



Ensure your webhook endpoint URL is exactly what the provider expects:





  • Protocol: HTTPS (not HTTP, unless testing locally)


  • Port: 443 for HTTPS, 80 for HTTP. Don't include :443 in the URL


  • Path: Match the exact path registered with the provider


  • Query parameters: Some providers allow them; others reject URLs with query strings




CODE
# Test your endpoint with curl, mimicking the provider's request
curl -X POST https://yourdomain.com/webhook \
-H "Content-Type: application/json" \
-H "X-Signature: your-signature-here" \
-d '{"event":"test","data":{}}'









Common Errors and Fixes






Error 1: "SyntaxError: Unexpected token < in JSON at position 0"



Root cause: Your endpoint is returning HTML (likely a 404 page or error page) instead of JSON. The provider is sending a valid webhook, but your server is routing it incorrectly.



Fix:




CODE
// Verify your route is registered BEFORE generic error handlers
app.post('/webhook', (req, res) => {
res.json({ received: true });
});

// Generic 404 handler comes AFTER specific routes
app.use((req, res) => {
res.status(404).json({ error: 'Not found' });
});

// Test the route exists
console.log(app._router.stack.filter(r => r.route?.path === '/webhook'));









Error 2: "413 Payload Too Large" or "Unexpected end of JSON input"



Root cause: Your middleware has a size limit that's too small, or the body parser is truncating large payloads.



Fix:




CODE
// Increase payload size limits
app.use(express.json({ limit: '50mb' }));
app.use(express.raw({ type: 'application/json', limit: '50mb' }));

// For Fastify
fastify.register(require('@fastify/raw-body'), { limit: '50mb' });









Frequently Asked Questions



Q: Why does my webhook handler return 200 but the provider shows it as failed?



A: The provider likely has a timeout (usually 5–30 seconds). If your handler takes longer, the provider cancels the request mid-response. Return 200 immediately, then process the payload asynchronously in a background job. Also verify you're actually returning 200 and not a 200 with an error body that the provider interprets as failure.



Q: Can I test webhook 400 errors locally without deploying?



A: Yes. Use a webhook inspector like Anonymily to capture payloads and replay them. The command npx @anonymilyhq/cli listen 3000 forwards webhooks to your local handler, and the dashboard lets you inspect exactly what failed. You can also replay requests to test fixes without waiting for the provider to retry.



Q: How do I know if the issue is my code or the provider's webhook?



A: Check your provider's webhook logs (Stripe Dashboard, GitHub Settings > Webhooks, etc.). If the provider shows a successful send but your server logs show nothing, the issue is networking or routing. If the provider shows a failed send, capture the request with a webhook inspector to see what was actually sent.






Next Steps



Start by capturing your next webhook with a local inspector. Run npx @anonymilyhq/cli listen 3000 and check the dashboard at to avoid port-forwarding complexity. For production, remember that Anonymily is a dev tool; for production receive-at-scale with retries and SLA, use Hookdeck or Svix.



The 400 error almost always traces back to raw body handling, signature verification, or routing. Debug methodically, capture the actual request, and you'll fix it in minutes.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Webhook 400 Bad Request: Debugging & Fixes

Thematisch verwandte Begriffe: Webhook, Request, Debugging, Fixes · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...