BerriAI/litellm · error · ValueError
Failed to decode JSON from chunk: {chunk}
Error message
Failed to decode JSON from chunk: {chunk} What it means
Thrown by the Anthropic streaming chunk parser when json.loads fails on a chunk it was handed. LiteLLM's Anthropic streaming handler parses each SSE data payload as JSON before converting it to a GenericStreamingChunk; if the payload is not valid JSON, the json.JSONDecodeError is re-raised as this ValueError. It almost always means the bytes coming off the HTTP stream are not a well-formed Anthropic SSE JSON event.
Source
Thrown at litellm/llms/anthropic/chat/handler.py:977
index=index,
delta=Delta(
content=text,
tool_calls=[tool_use] if tool_use is not None else None,
provider_specific_fields=(provider_specific_fields if provider_specific_fields else None),
thinking_blocks=(thinking_blocks if thinking_blocks else None),
reasoning_content=reasoning_content,
),
finish_reason=finish_reason,
)
],
usage=usage,
id=self.response_id,
)
return returned_chunk
except json.JSONDecodeError:
raise ValueError(f"Failed to decode JSON from chunk: {chunk}")
def _handle_json_mode_chunk(
self, text: str, tool_use: ChatCompletionToolCallChunk | None
) -> tuple[str, ChatCompletionToolCallChunk | None]:
"""
If JSON mode is enabled, convert the tool call to a message.
Anthropic returns the JSON schema as part of the tool call
OpenAI returns the JSON schema as part of the content, this handles placing it in the content
Tool streaming follows Anthropic's fine-grained streaming pattern:
- content_block_start: Contains complete tool info (id, name, empty arguments)
- content_block_delta: Contains argument deltas (partial_json)
- content_block_stop: Signals end of tool
Reference: https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/fine-grained-tool-streaming
Args:View on GitHub (pinned to 6c2dcb801b)
Solutions
- Reproduce with streaming disabled (stream=False) to see the raw body; if it is HTML/text, the problem is the endpoint or an intermediary, not your code.
- Inspect the {chunk} text in the message to identify what actually arrived (HTML error page, truncated JSON, empty string).
- If using a custom api_base or proxy, bypass it and call api.anthropic.com directly to confirm the proxy is mangling SSE frames.
- Ensure SSE is not buffered/compressed by intermediaries (disable gzip on the proxy, set 'Cache-Control: no-cache', flush per event).
- Upgrade LiteLLM — the accumulated-JSON flush logic in this iterator has had fixes for partial-JSON handling at stream end.
Example fix
# before
for chunk in completion(stream=True):
process(chunk) # ValueError kills the loop mid-stream
# after
for chunk in completion(stream=True):
try:
process(chunk)
except ValueError as e:
if "Failed to decode JSON from chunk" in str(e):
log.warning("malformed SSE frame, skipping: %s", e)
continue
raise Defensive patterns
Strategy: try-catch
Try / catch
try:
for chunk in stream:
consume(chunk)
except ValueError as e:
if "Failed to decode JSON" in str(e):
log.warning("malformed SSE frame: %s", e)
# keep partial content, do not retry the whole stream blindly
else:
raise Prevention
- Test streaming against api.anthropic.com directly before adding proxies.
- Disable SSE buffering and compression on any intermediary.
- Log raw frames at DEBUG level in staging to catch format drift early.
- Keep LiteLLM updated for partial-JSON flush fixes.
When it happens
Trigger: Iterating an anthropic/ streaming completion where a 'data:' payload contains malformed JSON: a proxy or gateway (e.g. nginx, Cloudflare, a custom LiteLLM proxy hop) that truncates or rewrites SSE frames; an upstream returning an HTML/text error page mid-stream; or accumulated partial JSON that was flushed without its remainder when the stream ended.
Common situations: Self-hosted LiteLLM proxy behind a buffering/rewriting proxy; Anthropic API base URL pointed at a third-party gateway that emits non-Anthropic SSE; truncation from aggressive read timeouts; occasionally a transient upstream 5xx body leaked into the stream.
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 parsing chunk: {e}, Received chunk: {chunk}
- Error parsing chunk: {e}, Received chunk: {chunk}
- Chunk cannot be parsed as JSON: {e}
- Error receiving chunk from stream: {e}
- Unable to get json response - {e}, Original Response: {raw_r
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/951b6211e33540e9.
Report an issue: GitHub.