headroomlabs-ai/headroom · error · ValueError
Request body must be a JSON object, not " + type(result).__n
Error message
Request body must be a JSON object, not " + type(result).__name__
What it means
Error "Request body must be a JSON object, not " + type(result).__name__" thrown in headroomlabs-ai/headroom.
Source
Thrown at headroom/proxy/helpers.py:2519
Clients like OpenAI Codex may send zstd, gzip, or deflate-compressed
request bodies. Starlette's ``request.json()`` does not decompress
automatically, causing a UnicodeDecodeError on compressed bytes.
This helper inspects ``Content-Encoding``, decompresses if needed,
then JSON-decodes the result. It raises ``ValueError`` on any
decompression or parse failure so callers can return a clean 400.
"""
raw = await _read_request_body_bytes(request)
# Decode and parse JSON
try:
text = raw.decode("utf-8")
except UnicodeDecodeError as exc:
raise ValueError(f"Request body is not valid UTF-8 (possibly compressed?): {exc}") from exc
result = json.loads(text)
if not isinstance(result, dict):
raise ValueError("Request body must be a JSON object, not " + type(result).__name__)
# Drop output-only blocks the request schema rejects (see
# ``strip_output_only_request_blocks``). Callers of this bytes-less reader
# (e.g. the Gemini path) re-serialize ``result`` themselves.
if strip_output_only_request_blocks(result.get("messages")):
logger.warning(
"removed output-only content block(s) (%s) from request messages "
"before forwarding (not valid on the request path)",
",".join(sorted(OUTPUT_ONLY_REQUEST_BLOCK_TYPES)),
)
return result
async def read_request_json_with_bytes(request: Request) -> tuple[dict[str, Any], bytes]:
"""Read JSON body AND return the original (decompressed) bytes.
Returned bytes are post-content-decoding (zstd/gzip/deflate/br areView on GitHub (pinned to 322425c43b)
Solutions
- Send a JSON object (`{...}`) as the request body, not an array or scalar
- Check the client code path that serializes the request — it may be double-encoding or sending a list
- Verify Content-Type: application/json matches the actual payload
When it happens
Trigger: Raised when a parsed JSON request body is not an object (e.g. an array or string), which the proxy handler cannot process.
Common situations: See trigger scenarios.
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/cf313e43a947632b.
Report an issue: GitHub.