{"record":{"id":"35d32f370ef3f4f4","repo":"headroomlabs-ai/headroom","slug":"request-body-is-not-valid-utf-8-possibly-compress","errorCode":null,"errorMessage":"Request body is not valid UTF-8 (possibly compressed?): {exc}","messagePattern":"Request body is not valid UTF-8 \\(possibly compressed\\?\\): (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"headroom/proxy/helpers.py","lineNumber":2515,"sourceCode":"\nasync def _read_request_json(request: Request) -> dict[str, Any]:\n    \"\"\"Read and parse JSON from a request, handling compressed bodies.\n\n    Clients like OpenAI Codex may send zstd, gzip, or deflate-compressed\n    request bodies.  Starlette's ``request.json()`` does not decompress\n    automatically, causing a UnicodeDecodeError on compressed bytes.\n\n    This helper inspects ``Content-Encoding``, decompresses if needed,\n    then JSON-decodes the result.  It raises ``ValueError`` on any\n    decompression or parse failure so callers can return a clean 400.\n    \"\"\"\n    raw = await _read_request_body_bytes(request)\n\n    # Decode and parse JSON\n    try:\n        text = raw.decode(\"utf-8\")\n    except UnicodeDecodeError as exc:\n        raise ValueError(f\"Request body is not valid UTF-8 (possibly compressed?): {exc}\") from exc\n\n    result = json.loads(text)\n    if not isinstance(result, dict):\n        raise ValueError(\"Request body must be a JSON object, not \" + type(result).__name__)\n\n    # Drop output-only blocks the request schema rejects (see\n    # ``strip_output_only_request_blocks``). Callers of this bytes-less reader\n    # (e.g. the Gemini path) re-serialize ``result`` themselves.\n    if strip_output_only_request_blocks(result.get(\"messages\")):\n        logger.warning(\n            \"removed output-only content block(s) (%s) from request messages \"\n            \"before forwarding (not valid on the request path)\",\n            \",\".join(sorted(OUTPUT_ONLY_REQUEST_BLOCK_TYPES)),\n        )\n\n    return result\n\n","sourceCodeStart":2497,"sourceCodeEnd":2533,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/proxy/helpers.py#L2497-L2533","documentation":"Error \"Request body is not valid UTF-8 (possibly compressed?): {exc}\" thrown in headroomlabs-ai/headroom.","triggerScenarios":"Raised when a request body cannot be decoded as UTF-8 after decompression, often because it is still compressed or is binary data.","commonSituations":"See trigger scenarios.","solutions":["Check whether the body is actually compressed but missing/incorrect Content-Encoding header — set the correct header on the client","Ensure the client sends UTF-8 encoded JSON","Inspect the underlying decode error {exc} to see where decoding failed"],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}