{"record":{"id":"753c4912bbf4cade","repo":"BerriAI/litellm","slug":"chat-provider-invalid-chunk-type-type-parsed-chu","errorCode":null,"errorMessage":"Chat provider: Invalid chunk type {type(parsed_chunk)}","messagePattern":"Chat provider: Invalid chunk type (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/completion_extras/litellm_responses_transformation/transformation.py","lineNumber":1226,"sourceCode":"\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\n        if event_type == \"response.created\":\n            # Initial response creation event\n            verbose_logger.debug(\"Chat provider: response.created -> %s\", parsed_chunk)\n            return ModelResponseStream(\n                choices=[","sourceCodeStart":1208,"sourceCodeEnd":1244,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/completion_extras/litellm_responses_transformation/transformation.py#L1208-L1244","documentation":"The chunk transformer raises when parsed_chunk is not a dict after BaseModel normalization — i.e. not a pydantic model, not a dict (e.g. a str, bytes, or arbitrary object). Events must arrive as deserialized objects; raw text frames or unparsed bytes are rejected.","triggerScenarios":"Passing raw SSE lines (strings) or bytes from httpx directly into chunk_parser; a custom deserializer returning json.dumps(...) output instead of json.loads(...) result.","commonSituations":"Hand-rolled SSE clients that forget json.loads on the data: payload; mixing sync/async iterators and accidentally yielding the iterator object; double-encoded JSON strings.","solutions":["json.loads each SSE data payload before handing it to the transformer","Skip non-data frames (event:, id:, comments) in your SSE reader","Let litellm's built-in streaming handle deserialization when possible"],"exampleFix":"# before\nasync for line in response.aiter_lines():\n    if line.startswith(\"data: \"):\n        out = transformer.chunk_parser(line[6:])  # raw str\n\n# after\nimport json\nasync for line in response.aiter_lines():\n    if line.startswith(\"data: \"):\n        payload = line[6:]\n        if payload == \"[DONE]\":\n            break\n        out = transformer.chunk_parser(json.loads(payload))","handlingStrategy":"type-guard","validationCode":"import json\n\ndef is_parsed_event(chunk) -> bool:\n    if isinstance(chunk, str):\n        try:\n            json.loads(chunk)\n            return False  # still a string: parse it first\n        except json.JSONDecodeError:\n            return False\n    return isinstance(chunk, dict)","typeGuard":"def is_event_dict(v) -> bool:\n    return isinstance(v, dict)","tryCatchPattern":"for raw in sse_lines:\n    payload = json.loads(raw[6:])\n    if not isinstance(payload, dict):\n        continue\n    out = transformer.chunk_parser(payload, ...)","preventionTips":["Always json.loads SSE data payloads before transformation","Never forward raw lines, bytes, or serialized JSON strings to chunk parsers"],"tags":["streaming","chunk-transformer","deserialization"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}