BerriAI/litellm · error · GigaChatError
Invalid JSON response: {raw_response.text}
Error message
Invalid JSON response: {raw_response.text} What it means
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.
Source
Thrown at litellm/llms/gigachat/chat/transformation.py:402
def transform_response(
self,
model: str,
raw_response: httpx.Response,
model_response: ModelResponse,
logging_obj: LiteLLMLoggingObj,
request_data: dict,
messages: list[AllMessageValues],
optional_params: dict,
litellm_params: dict,
encoding: Any,
api_key: str | None = None,
json_mode: bool | None = None,
) -> ModelResponse:
"""Transform GigaChat response to OpenAI format."""
try:
response_json: Final = raw_response.json()
except Exception:
raise GigaChatError(
status_code=raw_response.status_code,
message=f"Invalid JSON response: {raw_response.text}",
)
is_structured_output: Final = optional_params.get("_structured_output", False)
choices: Final = []
for choice in response_json.get("choices", []):
message_data = choice.get("message", {})
finish_reason = choice.get("finish_reason", "stop")
# Transform function_call to tool_calls or content
if finish_reason == "function_call" and message_data.get("function_call"):
func_call = message_data["function_call"]
args = func_call.get("arguments", {})
if is_structured_output:
# Convert to content for structured outputView on GitHub (pinned to 6c2dcb801b)
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.
Example fix
# before: proxy returns HTML, completion fails with 'Invalid JSON response: <html>...' os.environ["HTTPS_PROXY"] = "http://corp-proxy:3128" r = litellm.completion(model="gigachat/GigaChat-Pro", messages=[...]) # after: exclude GigaChat hosts from the proxy os.environ["NO_PROXY"] = "gigachat.devices.sberbank.ru,ngw.devices.sberbank.ru" r = litellm.completion(model="gigachat/GigaChat-Pro", messages=[...])
Defensive patterns
Strategy: try-catch
Validate before calling
import os
# Best pre-check: a canary completion whose response body must be JSON
# (cheap guard for proxy/WAF interference before real traffic)
resp = litellm.completion(
model="gigachat/GigaChat-Lite",
messages=[{"role": "user", "content": "ping"}],
)
assert resp.choices, "non-JSON/intercepted response would have thrown GigaChatError at transform time" Try / catch
from litellm.exceptions import APIError
try:
resp = litellm.completion(model="gigachat/GigaChat-Pro", messages=msgs)
except APIError as e:
msg = str(e)
if "Invalid JSON response" in msg:
if "<html" in msg.lower():
raise RuntimeError("HTML body received — proxy/WAF intercepting GigaChat traffic; check NO_PROXY") from e
raise RuntimeError("GigaChat returned non-JSON body; inspect embedded text and retry once") from e
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
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
- Error in response object format, got None
- Error parsing BFL response: {e}
- Error parsing initial response: {e}
- Error parsing BFL response: {e}
- Failed to parse OCI embed response as JSON: {e}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/96fe10b3f4490b8c.
Report an issue: GitHub.