BerriAI/litellm · error · ValueError

Chat provider: Empty parsed_chunk

Error message

Chat provider: Empty parsed_chunk

What it means

The chunk transformer raises when handed an empty/falsy parsed_chunk (None, empty dict). This method converts Responses API stream events into chat.completion.chunk objects for callers bridging a Responses stream into the chat-completions streaming shape; an empty event means the upstream event deserialization or a custom generator produced nothing.

Source

Thrown at litellm/completion_extras/litellm_responses_transformation/transformation.py:1221

            parsed_chunk: Dict containing the Responses API event chunk
            tool_call_index_map: Per-stream output_index -> sequential tool_call index map

        Returns:
            ModelResponseStream: OpenAI-formatted streaming chunk

        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)

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Skip empty events before transformation: `if not chunk: continue` in your generator
  2. If parsing SSE yourself, ignore comment lines (`:` prefix) and non-event frames instead of yielding empty dicts
  3. Log the raw event stream to find which frame produced the empty chunk

Example fix

# before
for chunk in sse_parser(raw_stream):
    transformed = transformer.chunk_parser(chunk)  # chunk may be {}

# after
for chunk in sse_parser(raw_stream):
    if not chunk:
        continue
    transformed = transformer.chunk_parser(chunk)
Defensive patterns

Strategy: validation

Validate before calling

def chunk_nonempty(chunk) -> bool:
    return bool(chunk)

Try / catch

for raw in event_source:
    if not raw:
        continue  # skip keep-alives/empties
    out = transformer.chunk_parser(raw, ...)

Prevention

When it happens

Trigger: A generator feeding the transformer yields None or {} — e.g. a custom SSE parser that emits empty placeholders on keep-alive/comment events, or middleware filtering events down to nothing.

Common situations: Custom streaming adapters between provider SSE and the bridge; proxies forwarding comment-only SSE lines as empty dicts; test fixtures with empty event dicts.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/2837748520485553. Report an issue: GitHub.