{"record":{"id":"232fecc3b115a53d","repo":"xtekky/gpt4free","slug":"invalid-json-data-rest","errorCode":null,"errorMessage":"Invalid JSON data: {rest}","messagePattern":"Invalid JSON data: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"g4f/requests/__init__.py","lineNumber":388,"sourceCode":"    await stop_browser()\n\n\nasync def sse_stream(iter_lines: AsyncIterator[bytes]) -> AsyncIterator[dict]:\n    if hasattr(iter_lines, \"content\"):\n        iter_lines = iter_lines.content\n    elif hasattr(iter_lines, \"iter_lines\"):\n        iter_lines = iter_lines.iter_lines()\n    async for line in iter_lines:\n        if line.startswith(b\"data:\"):\n            rest = line[5:].strip()\n            if not rest:\n                continue\n            if rest.startswith(b\"[DONE]\"):\n                break\n            try:\n                yield json.loads(rest)\n            except json.JSONDecodeError:\n                raise ValueError(f\"Invalid JSON data: {rest}\")\n\n\nasync def iter_lines(iter_response: AsyncIterator[bytes], delimiter=None):\n    \"\"\"\n    iterate streaming content line by line, separated by ``\\\\n``.\n\n    Copied from: https://requests.readthedocs.io/en/latest/_modules/requests/models/\n    which is under the License: Apache 2.0\n    \"\"\"\n    pending = None\n\n    async for chunk in iter_response:\n        if pending is not None:\n            chunk = pending + chunk\n        lines = chunk.split(delimiter) if delimiter else chunk.splitlines()\n        pending = (\n            lines.pop()\n            if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/xtekky/gpt4free/blob/973504e1770928ed5fb82f43da528f441ad9ddc3/g4f/requests/__init__.py#L370-L406","documentation":"Raised inside the SSE line parser in g4f/requests/__init__.py: for each `data:` line (after stripping and skipping empty/[DONE] lines) it calls json.loads; any line whose payload is not valid JSON raises this ValueError with the raw fragment. It means the remote sent a malformed or non-JSON payload inside a server-sent-events stream that the caller expected to be JSON frames.","triggerScenarios":"Streaming a provider response where a `data:` line contains HTML (error page), plain text keep-alives, or truncated JSON; a proxy or captive portal injecting non-JSON content; the provider changing its wire format so that lines like `data: event: ping` appear.","commonSituations":"Provider-side changes to streaming format; rate-limit or Cloudflare HTML challenge pages returned mid-stream instead of JSON; chunked transfer cutting a JSON object across lines when the stream was preprocessed incorrectly before being handed to this iterator.","solutions":["Log the offending `rest` fragment (it is included in the message) and match it against what the provider actually sends — usually it reveals an HTML error page or rate-limit notice.","If you control the request, re-send it with proper headers/cookies so the provider returns a genuine JSON SSE stream.","If parsing third-party streams where non-JSON keep-alive lines are legal, pre-filter lines before passing them to this iterator, or wrap the iteration and skip undecodable lines instead of failing the whole stream.","Check for provider API format changes and update g4f (`pip install -U g4f`) since provider adapters track wire formats."],"exampleFix":"// before\nasync for chunk in iter_lines(response, delimiter=b\"\\n\"):\n    data = json.loads(chunk[5:])  # crashes on non-JSON data: lines\n\n// after\nasync for obj in process_sse_lines(iter_lines(response)):  # library helper\n    ...  # or pre-filter: skip lines not starting with b'data:{' when keep-alives are plain text","handlingStrategy":"try-catch","validationCode":"import json\n\ndef is_json_sse_line(line: bytes) -> bool:\n    rest = line[5:].strip()\n    if not rest or rest.startswith(b\"[DONE]\"):\n        return False\n    try:\n        json.loads(rest)\n        return True\n    except json.JSONDecodeError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    async for obj in stream:\n        handle(obj)\nexcept ValueError as e:\n    # payload fragment is embedded in the message; treat stream as corrupt\n    log.warning(f\"SSE stream corrupt: {e}\"); raise StreamCorrupted(e)","preventionTips":["Treat any non-JSON `data:` fragment as an upstream signal (error page, rate limit) and surface it in logs.","Keep provider/g4f versions updated since SSE formats drift.","Do not preprocess SSE bytes in ways that split JSON objects across `data:` lines."],"tags":["sse","streaming","json","malformed-response","parsing"],"backgroundTag":null,"analyzedSha":"973504e1770928ed5fb82f43da528f441ad9ddc3","analyzedAt":"2026-08-14T23:45:32.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}