bytedance/deer-flow · warning · HTTPException

Missing X-GitHub-Event header

Error message

Missing X-GitHub-Event header

What it means

Raised by the GitHub webhook receiver with status 400 when the X-GitHub-Event header is absent or empty. The receiver needs the event name to route the payload (issues, pull_request, etc.), and real GitHub deliveries always include this header — its absence almost always means a misconfigured proxy stripped it or the sender is not GitHub.

Source

Thrown at backend/app/gateway/routers/github_webhooks.py:255

                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(
            "github_webhook delivery=%s | %s",
            x_github_delivery,
            _summarise_event(x_github_event, payload),

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Ensure the delivery path forwards all X-GitHub-* headers (nginx: verify proxy_set_header directives don't override them; in general avoid header allow-lists on this route).
  2. When testing manually, include -H 'X-GitHub-Event: push' (and the signature header).
  3. Point health checks at /health, not the webhook endpoint.

Example fix

# before
curl -X POST https://host/api/webhooks/github --data-binary @payload.json
# -> 400 Missing X-GitHub-Event header

# after
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

# nginx: forward GitHub headers untouched
location /api/webhooks/github {
    proxy_pass http://gateway:8001;
    # do NOT override X-GitHub-* headers; avoid allow-lists on this route
}

Prevention

When it happens

Trigger: Manual curl/Postman testing without the X-GitHub-Event header; nginx or an API gateway dropping custom X-GitHub-* headers; corporate proxies stripping unknown X- headers; load-balancer health checks POSTing to the webhook URL.

Common situations: Proxy config with a header allow-list that omits GitHub's custom headers; webhook URL reused as a generic POST target in monitoring; incorrect ingress annotation like 'proxy_set_header X-GitHub-Event ""'.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/d7911340056da762. Report an issue: GitHub.