can1357/oh-my-pi · info · HTTPException

invalid json: {exc}

Error message

invalid json: {exc}

What it means

After signature verification, /webhook/github parses the request body as JSON; any parsing exception is converted to HTTP 400 with 'invalid json: <exc>', keeping malformed payloads out of the dispatcher while still returning 202-shaped semantics for valid ones.

Source

Thrown at python/robomp/src/server.py:346

    async def webhook(
        request: Request,
        x_github_event: str = Header(..., alias="X-GitHub-Event"),
        x_github_delivery: str = Header(..., alias="X-GitHub-Delivery"),
        x_hub_signature_256: str | None = Header(None, alias="X-Hub-Signature-256"),
    ) -> JSONResponse:
        bag = request.app.state.bag
        cfg: Settings = bag["settings"]
        body = await request.body()
        if not github_events.verify_signature(
            cfg.github_webhook_secret.get_secret_value(),
            body,
            x_hub_signature_256,
        ):
            raise HTTPException(status.HTTP_401_UNAUTHORIZED, "invalid signature")
        try:
            payload = await request.json()
        except Exception as exc:
            raise HTTPException(status.HTTP_400_BAD_REQUEST, f"invalid json: {exc}") from exc

        db: Database = bag["db"]
        issue_cache: _IssueBrowseCache = bag["issue_browse_cache"]
        await issue_cache.apply_webhook(
            event_type=x_github_event,
            payload=payload,
            allowlist=cfg.repo_allowlist,
        )
        # Keep the local search index fresh from every delivery that carries an
        # issue/PR object — including ones the router will skip.
        if x_github_event in ("issues", "issue_comment") or x_github_event.startswith("pull_request"):
            repo_full = str((payload.get("repository") or {}).get("full_name") or "")
            if repo_full and repo_full in cfg.repo_allowlist:
                try:
                    issue_index.ingest_webhook_payload(db, repo_full, x_github_event, payload)
                except Exception:
                    log.exception("issue index webhook ingest failed", extra={"repo": repo_full})

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure the client sends Content-Type: application/json with a well-formed JSON body.
  2. If testing manually, send the exact delivery JSON GitHub shows in 'Recent Deliveries'.
  3. Check intermediary proxies for body truncation or compression issues.
  4. Real GitHub webhooks are always JSON — if this recurs in production, inspect what is actually posting to the endpoint.

Example fix

// before
curl -X POST http://host:8080/webhook/github -d 'not json'
// after
curl -X POST http://host:8080/webhook/github \
  -H 'Content-Type: application/json' \
  --data-binary @payload.json
Defensive patterns

Strategy: validation

Validate before calling

import json
payload = json.loads(body)  # validate before sending
assert isinstance(payload, dict) and 'action' in payload

Try / catch

try:
    resp = httpx.post(url, json=payload, headers=headers)
except httpx.HTTPStatusError as e:
    if e.response.status_code == 400:
        ...  # read 'invalid json: ...' detail and fix the payload

Prevention

When it happens

Trigger: A request passing HMAC check whose body is not valid JSON — sender posting form-encoded data, truncated body, wrong Content-Type with binary payload, or a test curl with malformed JSON.

Common situations: Hand-testing the endpoint with curl and a typo'd payload; a proxy that decompresses/re-encodes incorrectly; sending GitHub's urlencoded ping form instead of JSON; empty body with valid signature computed over the empty string.

Understand the failure class

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/0aa321892dcba4cd. Report an issue: GitHub.