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 are

View on GitHub (pinned to 322425c43b)

Solutions

  1. Send a JSON object (`{...}`) as the request body, not an array or scalar
  2. Check the client code path that serializes the request — it may be double-encoding or sending a list
  3. 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.