{"record":{"id":"96fe10b3f4490b8c","repo":"BerriAI/litellm","slug":"invalid-json-response-raw-response-text","errorCode":null,"errorMessage":"Invalid JSON response: {raw_response.text}","messagePattern":"Invalid JSON response: (.+?)","errorType":"exception","errorClass":"GigaChatError","httpStatus":null,"severity":"error","filePath":"litellm/llms/gigachat/chat/transformation.py","lineNumber":402,"sourceCode":"    def transform_response(\n        self,\n        model: str,\n        raw_response: httpx.Response,\n        model_response: ModelResponse,\n        logging_obj: LiteLLMLoggingObj,\n        request_data: dict,\n        messages: list[AllMessageValues],\n        optional_params: dict,\n        litellm_params: dict,\n        encoding: Any,\n        api_key: str | None = None,\n        json_mode: bool | None = None,\n    ) -> ModelResponse:\n        \"\"\"Transform GigaChat response to OpenAI format.\"\"\"\n        try:\n            response_json: Final = raw_response.json()\n        except Exception:\n            raise GigaChatError(\n                status_code=raw_response.status_code,\n                message=f\"Invalid JSON response: {raw_response.text}\",\n            )\n\n        is_structured_output: Final = optional_params.get(\"_structured_output\", False)\n\n        choices: Final = []\n        for choice in response_json.get(\"choices\", []):\n            message_data = choice.get(\"message\", {})\n            finish_reason = choice.get(\"finish_reason\", \"stop\")\n\n            # Transform function_call to tool_calls or content\n            if finish_reason == \"function_call\" and message_data.get(\"function_call\"):\n                func_call = message_data[\"function_call\"]\n                args = func_call.get(\"arguments\", {})\n\n                if is_structured_output:\n                    # Convert to content for structured output","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/gigachat/chat/transformation.py#L384-L420","documentation":"Raised by GigaChat's transform_response when raw_response.json() throws for any reason — the completion endpoint returned a body that is not valid JSON. The GigaChatError reuses the upstream status_code and puts raw_response.text in the message, so you can see whether you got an HTML error page, a plain-text 502 from a load balancer, or an empty body. Note the bare `except Exception` means JSONDecodeError and any content-decoding error both land here.","triggerScenarios":"POST to the GigaChat completion API returns non-JSON: an HTML block page from a corporate proxy/WAF (often with HTTP 200 or 403), a gateway 502/504 HTML page, a truncated body from a dropped connection, or a text error like 'rate limit exceeded' served without JSON. Also occurs when custom GIGACHAT_API_BASE points at a non-GigaChat server.","commonSituations":"TLS-intercepting corporate proxies replacing responses; SberCloud/GigaChat maintenance windows returning HTML status pages; slow streaming responses cut off mid-body; api_base typos hitting an unrelated web server that returns HTML 404s.","solutions":["Read the raw body embedded in the error message — HTML titles like '403 Forbidden' or 'Maintenance' identify the interceptor immediately.","If a proxy sits in the path, bypass or allowlist the GigaChat hosts so JSON responses pass through untouched.","Confirm GIGACHAT_API_BASE is correct (default https://gigachat.devices.sberbank.ru/api/v1) and not pointing at an HTML-serving host.","Retry transiently — truncated bodies from dropped connections resolve on retry; persistent HTML responses indicate configuration/interception, not flakiness."],"exampleFix":"# before: proxy returns HTML, completion fails with 'Invalid JSON response: <html>...'\nos.environ[\"HTTPS_PROXY\"] = \"http://corp-proxy:3128\"\nr = litellm.completion(model=\"gigachat/GigaChat-Pro\", messages=[...])\n\n# after: exclude GigaChat hosts from the proxy\nos.environ[\"NO_PROXY\"] = \"gigachat.devices.sberbank.ru,ngw.devices.sberbank.ru\"\nr = litellm.completion(model=\"gigachat/GigaChat-Pro\", messages=[...])","handlingStrategy":"try-catch","validationCode":"import os\n\n# Best pre-check: a canary completion whose response body must be JSON\n# (cheap guard for proxy/WAF interference before real traffic)\nresp = litellm.completion(\n    model=\"gigachat/GigaChat-Lite\",\n    messages=[{\"role\": \"user\", \"content\": \"ping\"}],\n)\nassert resp.choices, \"non-JSON/intercepted response would have thrown GigaChatError at transform time\"","typeGuard":null,"tryCatchPattern":"from litellm.exceptions import APIError\n\ntry:\n    resp = litellm.completion(model=\"gigachat/GigaChat-Pro\", messages=msgs)\nexcept APIError as e:\n    msg = str(e)\n    if \"Invalid JSON response\" in msg:\n        if \"<html\" in msg.lower():\n            raise RuntimeError(\"HTML body received — proxy/WAF intercepting GigaChat traffic; check NO_PROXY\") from e\n        raise RuntimeError(\"GigaChat returned non-JSON body; inspect embedded text and retry once\") from e\n    raise","preventionTips":["Add GigaChat hosts to NO_PROXY when corporate proxies intercept HTTPS.","Alert on response bodies starting with '<' — earliest signal of interception.","Retry once on truncated-body failures; escalate if the same HTML/text body repeats.","Verify GIGACHAT_API_BASE points at the real API host, not an HTML-serving gateway."],"tags":["gigachat","response-parsing","json","proxy","httpx"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}