can1357/oh-my-pi · error · HTTPException
invalid json: {exc}
Error message
invalid json: {exc} What it means
_json_body parses the request body as JSON for all write endpoints (post_comment, open_pull_request, request_reviewers, etc.). If request.json() raises for any reason, the proxy returns HTTP 400 'invalid json: <detail>'. A non-dict JSON value (array, string, number) gets a separate 'json body must be an object' error.
Source
Thrown at python/robomp/src/proxy/server.py:656
return JSONResponse({"items": [_serialize(c) for c in items]})
@app.get("/gh/v1/pr_reviews")
async def list_pr_reviews(request: Request, repo: str, pr_number: int) -> JSONResponse:
await _authenticate(request)
github: GitHubClient = request.app.state.github
try:
items = await github.list_pr_reviews(repo, pr_number)
except GitHubError as exc:
return _gh_error_response(exc)
return JSONResponse({"items": [_serialize(r) for r in items]})
# ---- writes ----
async def _json_body(request: Request) -> dict[str, Any]:
await _authenticate(request)
try:
data = await request.json()
except Exception as exc:
raise HTTPException(400, f"invalid json: {exc}") from exc
if not isinstance(data, dict):
raise HTTPException(400, "json body must be an object")
return data
@app.post("/gh/v1/post_comment")
async def post_comment(request: Request) -> JSONResponse:
data = await _json_body(request)
repo = _require_str(data.get("repo"), "repo")
number = _require_int(data.get("number"), "number")
body = _require_str(data.get("body"), "body")
github: GitHubClient = request.app.state.github
try:
info = await github.post_comment(repo, number, body)
except GitHubError as exc:
return _gh_error_response(exc)
return JSONResponse(_serialize(info))
@app.post("/gh/v1/open_pull_request")View on GitHub (pinned to 9690622007)
Solutions
- Serialize the body with a JSON encoder and send it with Content-Type: application/json
- Validate the body parses locally with JSON.parse before sending to isolate client vs server issues
- Ensure the full body is transmitted (correct Content-Length, no truncation) and not form-encoded
Example fix
// before
curl -X POST $PROXY/gh/v1/post_comment -d '{issue: 1, body: "hi"}'
// after
curl -X POST $PROXY/gh/v1/post_comment \
-H 'Content-Type: application/json' \
-d '{"issue": 1, "body": "hi"}' Defensive patterns
Strategy: try-catch
Validate before calling
const payload = JSON.stringify(args); // never hand-build JSON
JSON.parse(payload); // optional local round-trip check
if (!args || typeof args !== "object" || Array.isArray(args)) throw new Error("json body must be an object"); Type guard
function isJsonObject(v: unknown): v is Record<string, unknown> {
return typeof v === "object" && v !== null && !Array.isArray(v);
} Try / catch
try {
const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
if (res.status === 400) {
const detail = await res.text();
throw new Error(`request rejected: ${detail}`); // includes 'invalid json: ...'
}
} catch (err) { /* handle */ } Prevention
- Always build bodies with JSON.stringify, never string concatenation
- Send Content-Type: application/json on every write request
- Validate the payload is a plain object before sending
- Check for empty/truncated bodies in intermediaries (proxies, retry wrappers)
When it happens
Trigger: POSTing to a /gh/v1 write endpoint with a body that is empty, truncated, not valid JSON (unquoted keys, trailing commas, single quotes), sent with the wrong Content-Type, or with a body consumed/corrupted by middleware.
Common situations: Hand-built request bodies via string concatenation instead of JSON.stringify; double-encoding (sending a JSON string of JSON); empty body on POST; curl without -d quoting; clients sending form-encoded data where JSON is expected.
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
- Replacement text is not valid UTF-8: {err}
- V2 compaction stream parse failed: ${err instanceof Error ?
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE must contain a JSON object
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains an empty provider
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains a provider id wit
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/17034acc02740fc8.
Report an issue: GitHub.