BerriAI/litellm · error · ValueError
Chat provider: Invalid chunk type
Error message
Chat provider: Invalid chunk type {type(parsed_chunk)} What it means
After converting BaseModel inputs via model_dump, translate_responses_chunk_to_openai_stream requires the chunk to be a dict. A chunk that is a string (e.g. a raw 'data: {...}' SSE line), a list, or any other type cannot be inspected for type/object/choices fields and is rejected with the actual type in the message. It marks a feeding bug: un-parsed or wrongly-parsed events reaching the translator.
Solutions
- Parse every SSE data line with json.loads after stripping the 'data:' prefix, and pass the resulting dict
- Check for double-encoded payloads: if json.loads returns a str, json.loads it again
- Yield one parsed event per call — never a list or generator of events
- Log type(parsed_chunk) at the boundary feeding the translator to catch regressions
Example fix
// before
for line in response.iter_lines():
out = translate_responses_chunk_to_openai_stream(line) # line is 'data: {...}' -> ValueError: Chat provider: Invalid chunk type <class 'str'>
// after
import json
for line in response.iter_lines():
if not line or not line.startswith("data:"):
continue
out = translate_responses_chunk_to_openai_stream(json.loads(line[len("data:"):])) Defensive patterns
Strategy: type-guard
Validate before calling
import json
def parsed_chunk_is_dict(chunk):
if isinstance(chunk, str):
chunk = json.loads(chunk.lstrip("data:").strip() if chunk.startswith("data:") else chunk)
return chunk Type guard
def is_translatable_chunk(chunk) -> bool:
return isinstance(chunk, dict) or hasattr(chunk, "model_dump") Try / catch
try:
out = translate_responses_chunk_to_openai_stream(chunk)
except ValueError as e:
if "Invalid chunk type" in str(e):
import json
out = translate_responses_chunk_to_openai_stream(json.loads(chunk)) # chunk was a raw JSON string
else:
raise Prevention
- Strip 'data:' prefixes and json.loads every SSE line before translation
- Guard against double-encoded JSON (json.loads returning str) at the parse boundary
- Log type(chunk) where streams enter your code to catch shape regressions early
When it happens
Trigger: Passing raw SSE text lines instead of parsed JSON objects; double-encoded JSON where json.loads returns a string; forwarding a list of events as a single chunk; custom iterators yielding tuples/objects the translator does not know.
Common situations: Hand-rolled SSE clients that forget to strip the 'data:' prefix or to json.loads; gateways that wrap payloads in quoted strings; test fixtures building chunks as JSON strings; refactors that changed what the upstream iterator yields.
Related errors
- Chat provider: Empty parsed_chunk
- Chat provider: Invalid function argument delta
- Stream completed response is invalid
- Chunk cannot be parsed as CohereStreamChunk
- Error parsing chunk: , Received chunk
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/753c4912bbf4cade.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/completion_extras/litellm_responses_transformation/transformation.py:1228
Raises:
ValueError: If chunk is invalid or missing required fields
"""
from litellm.types.llms.openai import ChatCompletionToolCallFunctionChunk
from litellm.types.utils import (
ChatCompletionToolCallChunk,
Delta,
ModelResponseStream,
StreamingChoices,
)
if not parsed_chunk:
raise ValueError("Chat provider: Empty parsed_chunk")
if isinstance(parsed_chunk, BaseModel):
parsed_chunk = parsed_chunk.model_dump()
if not isinstance(parsed_chunk, dict):
raise ValueError(f"Chat provider: Invalid chunk type {type(parsed_chunk)}")
# Handle different event types from responses API
event_type = parsed_chunk.get("type")
if isinstance(event_type, ResponsesAPIStreamEvents):
event_type = event_type.value
if parsed_chunk.get("object") == "chat.completion.chunk" or (
event_type is None and isinstance(parsed_chunk.get("choices"), list) and parsed_chunk.get("choices")
):
return ModelResponseStream(**parsed_chunk)
verbose_logger.debug("Chat provider: Processing event type: %s", event_type)
if event_type == "response.created":
# Initial response creation event
verbose_logger.debug("Chat provider: response.created -> %s", parsed_chunk)
return ModelResponseStream(
choices=[View on GitHub (pinned to 77b7c6c40c)