bytedance/deer-flow · warning · HTTPException
Invalid JSON body
Error message
Invalid JSON body
What it means
Raised by the GitHub webhook receiver with status 400 when the (already signature-verified) request body fails json.loads — the payload is not valid JSON. Because verification happens first, a 400 here with a valid signature usually means GitHub sent an empty or non-JSON body, or the proxy corrupted the body after signature-relevant bytes (empty body maps to {}, so this specifically means non-empty, unparseable bytes).
Source
Thrown at backend/app/gateway/routers/github_webhooks.py:267
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(
"github_webhook delivery=%s | %s",
x_github_delivery,
_summarise_event(x_github_event, payload),
)
handled = True
# Publish inbound messages onto the channel bus so the
# ChannelManager picks them up and routes them to the right
# custom agents. No direct agent-run calls here.
from app.channels.service import get_channel_service
service = get_channel_service()
if service is None:
# Permanent state, not a transient failure: ``channels.github``
# is not enabled in this deployment. Returning 503 would mark
# this delivery "failed" and invite a manual "Redeliver" or anView on GitHub (pinned to 1dd6ba1acb)
Solutions
- In GitHub webhook/App settings, set Content type to application/json.
- Verify the proxy forwards the body unmodified and handles content-encoding (identity or properly decoded).
- For manual tests, validate the file first: python -m json.tool payload.json.
Example fix
# before: GitHub webhook content type = application/x-www-form-urlencoded # payload arrives as 'payload=%7B...%7D' -> 400 Invalid JSON body # after: GitHub repo Settings -> Webhooks -> Edit -> Content type = application/json # then click 'Redeliver' on a recent delivery
Defensive patterns
Strategy: validation
Validate before calling
const okPayload = (raw: string) => { try { JSON.parse(raw); return true; } catch { return false; } };
if (!okPayload(body)) throw new Error('webhook body is not JSON — check GitHub content type'); Prevention
- Set GitHub webhook Content type to application/json
- Validate payloads locally before replay scripts
- Ensure proxies don't truncate or re-encode bodies
When it happens
Trigger: Sending form-encoded (application/x-www-form-urlencoded) payloads instead of JSON — GitHub does this when the webhook content-type is configured as form; proxies mangling the body (truncation, chunked-encoding bugs); handcrafted test requests with malformed JSON.
Common situations: GitHub webhook 'Content type' set to application/x-www-form-urlencoded in repo settings; gzip/deflate content-encoding not decoded by an intermediary; truncated bodies from MTU/proxy limits.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Missing X-GitHub-Event header
- Webhook signature verification not configured. Set {_SECRET_
- Invalid or missing X-Hub-Signature-256
- {e}
- Only files in /mnt/user-data/outputs can be edited
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/21c70ba827f998e3.
Report an issue: GitHub.