{"record":{"id":"447feb6423256b83","repo":"BerriAI/litellm","slug":"chunk-does-not-start-with-data-chunk","errorCode":null,"errorMessage":"Chunk does not start with 'data:': {chunk}","messagePattern":"Chunk does not start with 'data:': (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/oci/chat/transformation.py","lineNumber":750,"sourceCode":"            make_call=make_call,\n            _response_headers=_response_headers,\n        )\n        # Tracks whether any prior Cohere chunk in this stream has emitted\n        # tool calls. The Cohere handler uses this to decide whether the\n        # terminal consolidation chunk's tool calls are duplicates (suppress)\n        # or the only copy of the tool calls (pass through).\n        self._cohere_tool_calls_emitted = False\n        # Analogous flag for text content. Lets the Cohere handler distinguish\n        # the common case (prior deltas already streamed the text, so the\n        # terminal chunk's text is a duplicate to suppress) from the degenerate\n        # single-event case (terminal chunk carries the only copy of the text).\n        self._cohere_text_emitted = False\n\n    def chunk_creator(self, chunk: Any) -> ModelResponseStream:\n        if not isinstance(chunk, str):\n            raise ValueError(f\"Chunk is not a string: {chunk}\")\n        if not chunk.startswith(\"data:\"):\n            raise ValueError(f\"Chunk does not start with 'data:': {chunk}\")\n        try:\n            dict_chunk: Final = json.loads(chunk[5:])\n        except json.JSONDecodeError as e:\n            raise OCIError(\n                status_code=500,\n                message=f\"Chunk cannot be parsed as JSON: {e}\",\n            )\n\n        if dict_chunk.get(\"apiFormat\") == \"COHERE\":\n            result: Final = handle_cohere_stream_chunk(\n                dict_chunk,\n                prior_tool_calls_emitted=self._cohere_tool_calls_emitted,\n                prior_text_emitted=self._cohere_text_emitted,\n            )\n            if not self._cohere_tool_calls_emitted:\n                for choice in result.choices:\n                    if getattr(choice.delta, \"tool_calls\", None) is not None:\n                        self._cohere_tool_calls_emitted = True","sourceCodeStart":732,"sourceCodeEnd":768,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/oci/chat/transformation.py#L732-L768","documentation":"chunk_creator requires every chunk to start with the literal 'data:' prefix (the SSE event-field format OCI uses). A chunk lacking that prefix — e.g. a comment line ':ping', an 'event:' line, a blank line, or leading whitespace — raises ValueError because the parser does not attempt generic SSE framing.","triggerScenarios":"The stream yields lines like 'event: message', ':keep-alive', or an empty string; typically from a nonstandard intermediary that alters SSE framing, or from manual iteration that splits on the wrong boundary and passes partial/garbled lines into chunk_creator.","commonSituations":"Corporate proxies or API gateways injecting keep-alive comments; misconfigured buffering that merges or truncates SSE lines; test harnesses yielding raw JSON without the 'data:' prefix. Normal direct-to-OCI streaming never produces these lines.","solutions":["Ensure no intermediary rewrites the SSE stream (disable response buffering on gateways, use passthrough proxies).","If iterating manually, filter to lines starting with 'data:' before calling chunk_creator.","Re-run against the OCI endpoint directly to confirm the raw stream framing.","Check for litellm updates if the SSE line-splitting logic changed."],"exampleFix":"# before\nfor chunk in wrapper.completion_stream:\n    model_chunk = handler.chunk_creator(chunk)  # blows up on ': ping'\n\n# after\nfor chunk in wrapper.completion_stream:\n    if not isinstance(chunk, str) or not chunk.startswith(\"data:\"):\n        continue\n    model_chunk = handler.chunk_creator(chunk)","handlingStrategy":"validation","validationCode":"chunk = chunk if isinstance(chunk, str) else \"\"\nif not chunk.startswith(\"data:\"):\n    continue  # skip comments/events/blank lines","typeGuard":"def is_data_event(line: object) -> bool:\n    return isinstance(line, str) and line.startswith(\"data:\")","tryCatchPattern":"try:\n    model_chunk = handler.chunk_creator(chunk)\nexcept ValueError as e:\n    if \"does not start with 'data:'\" in str(e):\n        continue  # tolerate non-data SSE lines\n    raise","preventionTips":["Filter SSE lines to 'data:' events before parsing when consuming raw streams.","Disable proxy buffering/rewrite of SSE responses.","Prefer litellm's stream iterator over manual SSE handling."],"tags":["oci","streaming","sse","parsing"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}