bytedance/deer-flow · error · HTTPException
Invalid or missing X-Hub-Signature-256
Error message
Invalid or missing X-Hub-Signature-256
What it means
Raised by the GitHub webhook receiver with status 401 when a secret IS configured but the X-Hub-Signature-256 header is missing or does not match HMAC-SHA256(secret, raw_body). The receiver verifies the signature over the exact raw request bytes before parsing JSON (verify-then-parse), so any body mutation by a proxy breaks it.
Source
Thrown at backend/app/gateway/routers/github_webhooks.py:252
)
raise HTTPException(
status_code=503,
detail=f"Webhook signature verification not configured. Set {_SECRET_ENV_VAR} or {_ALLOW_UNVERIFIED_ENV_VAR}=1 for unverified dev mode.",
)
logger.warning(
"github_webhook: accepting UNVERIFIED delivery (event=%s delivery=%s). %s=1 is set — dev/loopback mode ONLY. Do not use in production.",
x_github_event,
x_github_delivery,
_ALLOW_UNVERIFIED_ENV_VAR,
)
else:
if not _verify_signature(secret, body, x_hub_signature_256):
logger.warning(
"github_webhook: signature verification FAILED (event=%s delivery=%s)",
x_github_event,
x_github_delivery,
)
raise HTTPException(status_code=401, detail="Invalid or missing X-Hub-Signature-256")
if not x_github_event:
raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
# Parse JSON payload after signature is verified (verify-then-parse).
try:
payload: dict[str, Any] = json.loads(body) if body else {}
except json.JSONDecodeError as exc:
logger.warning(
"github_webhook: invalid JSON body (event=%s delivery=%s): %s",
x_github_event,
x_github_delivery,
exc,
)
raise HTTPException(status_code=400, detail="Invalid JSON body") from exc
if x_github_event in _KNOWN_EVENTS:
logger.info(View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Re-sync the secret: set the identical value in the GitHub App/webhook settings and the Gateway env var, then redeliver from GitHub's webhook UI.
- Ensure the reverse proxy passes the request body through byte-for-byte untouched (no body filters/rewrites) and forwards the X-Hub-Signature-256 header.
- When testing manually, compute the header: sha256 hex of HMAC over the exact body bytes you send.
Example fix
# before (test client sends no/incorrect signature)
curl -X POST https://host/api/webhooks/github -H 'X-GitHub-Event: push' -d @payload.json
# -> 401 Invalid or missing X-Hub-Signature-256
# after
SIG=$(openssl dgst -sha256 -hmac "$GITHUB_WEBHOOK_SECRET" -hex < payload.json | awk '{print $2}')
curl -X POST https://host/api/webhooks/github \
-H "X-GitHub-Event: push" \
-H "X-Hub-Signature-256: sha256=$SIG" \
--data-binary @payload.json Defensive patterns
Strategy: validation
Validate before calling
# verify locally before sending: HMAC over exact body bytes import hmac, hashlib sig = 'sha256=' + hmac.new(secret.encode(), body_bytes, hashlib.sha256).hexdigest() assert sig == sent_header, 'signature mismatch — check secret and body bytes'
Try / catch
try { await deliver(); } catch (e) { if (e.status === 401) { await resyncWebhookSecret(); await redeliver(); } throw e; } Prevention
- Keep the GitHub-side and Gateway-side secret identical
- Never let proxies rewrite the request body on the webhook route
- Use --data-binary (no re-encoding) when testing
When it happens
Trigger: GitHub webhook secret in repo settings differs from the Gateway's configured secret; an intermediate proxy (nginx with body rewrite, request modification, or re-encoding) altering the raw body; replaying a captured request with a modified payload; missing signature header from a non-Github sender.
Common situations: Secret regenerated on one side only; nginx lua/scripts rewriting request bodies; line-ending or encoding transformations; load balancer appending trailers; using a test client that doesn't compute the HMAC.
Related errors
- Webhook signature verification not configured. Set {_SECRET_
- Missing X-GitHub-Event header
- Invalid JSON body
- Authentication required
- NOT_AUTHENTICATED
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/b944a19572b4d657.
Report an issue: GitHub.