{"record":{"id":"2837748520485553","repo":"BerriAI/litellm","slug":"chat-provider-empty-parsed-chunk","errorCode":null,"errorMessage":"Chat provider: Empty parsed_chunk","messagePattern":"Chat provider: Empty parsed_chunk","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/completion_extras/litellm_responses_transformation/transformation.py","lineNumber":1223,"sourceCode":"            parsed_chunk: Dict containing the Responses API event chunk\n            tool_call_index_map: Per-stream output_index -> sequential tool_call index map\n\n        Returns:\n            ModelResponseStream: OpenAI-formatted streaming chunk\n\n        Raises:\n            ValueError: If chunk is invalid or missing required fields\n        \"\"\"\n        from litellm.types.llms.openai import ChatCompletionToolCallFunctionChunk\n        from litellm.types.utils import (\n            ChatCompletionToolCallChunk,\n            Delta,\n            ModelResponseStream,\n            StreamingChoices,\n        )\n\n        if not parsed_chunk:\n            raise ValueError(\"Chat provider: Empty parsed_chunk\")\n\n        if isinstance(parsed_chunk, BaseModel):\n            parsed_chunk = parsed_chunk.model_dump()\n        if not isinstance(parsed_chunk, dict):\n            raise ValueError(f\"Chat provider: Invalid chunk type {type(parsed_chunk)}\")\n\n        # Handle different event types from responses API\n        event_type = parsed_chunk.get(\"type\")\n        if isinstance(event_type, ResponsesAPIStreamEvents):\n            event_type = event_type.value\n\n        if parsed_chunk.get(\"object\") == \"chat.completion.chunk\" or (\n            event_type is None and isinstance(parsed_chunk.get(\"choices\"), list) and parsed_chunk.get(\"choices\")\n        ):\n            return ModelResponseStream(**parsed_chunk)\n\n        verbose_logger.debug(\"Chat provider: Processing event type: %s\", event_type)\n","sourceCodeStart":1205,"sourceCodeEnd":1241,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/completion_extras/litellm_responses_transformation/transformation.py#L1205-L1241","documentation":"translate_responses_chunk_to_openai_stream requires a truthy parsed_chunk: passing None, an empty dict, or another falsy value is rejected before any event handling. The translator runs inside litellm's streaming bridge, so end users see it when the provider's SSE stream contains events that decode to nothing (blank data lines, empty JSON objects) and reach the translator unfiltered, or when the API is called directly with a falsy chunk.","triggerScenarios":"A provider or gateway emitting empty SSE 'data:' lines or '{}' events that get parsed and forwarded; keep-alive/comment frames mis-parsed as chunks; custom code calling the translator with a chunk variable that is None after a failed parse; double-processing a stream where exhaustion yields None.","commonSituations":"Non-OpenAI-compatible gateways in front of a Responses API; brittle custom SSE parsing; streaming tests feeding fabricated chunk sequences; older litellm versions lacking empty-event filtering.","solutions":["Skip falsy chunks before translating: 'if not chunk: continue' in any custom loop","Upgrade litellm — empty-event filtering in the responses stream iterator has been tightened over releases","Inspect the raw SSE frames (verbose logging) to find which event decodes to empty and report/fix the gateway","Ensure json.loads results are checked for None/{} in custom parsing code"],"exampleFix":"// before\nfor raw in sse_lines:\n    chunk = json.loads(raw) if raw.startswith(\"data:\") else None\n    out = translate_responses_chunk_to_openai_stream(chunk)  # ValueError: Chat provider: Empty parsed_chunk\n\n// after\nfor raw in sse_lines:\n    if not raw.startswith(\"data:\"):\n        continue\n    chunk = json.loads(raw[5:])\n    if not chunk:\n        continue\n    out = translate_responses_chunk_to_openai_stream(chunk)","handlingStrategy":"validation","validationCode":"def chunk_is_translatable(chunk) -> bool:\n    return bool(chunk)","typeGuard":"def is_nonempty_chunk(chunk) -> bool:\n    return bool(chunk) and (isinstance(chunk, dict) or hasattr(chunk, \"model_dump\"))","tryCatchPattern":"try:\n    out = translate_responses_chunk_to_openai_stream(chunk)\nexcept ValueError as e:\n    if \"Empty parsed_chunk\" in str(e):\n        continue  # skip empty event, keep consuming the stream\n    raise","preventionTips":["Filter falsy chunks before translation in any custom streaming loop","Check json.loads results for None/{} and skip them","Upgrade litellm so the built-in iterator filters empty SSE events for you"],"tags":["streaming","sse","responses-api","validation"],"backgroundTag":"empty-chunk-stream","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}