{"record":{"id":"71d1912543ea6a9d","repo":"PaddlePaddle/PaddleOCR","slug":"malformed-jsonl-result-payload-e-71d191","errorCode":null,"errorMessage":"Malformed JSONL result payload: {e}","messagePattern":"Malformed JSONL result payload: (.+?)","errorType":"exception","errorClass":"ResultParseError","httpStatus":null,"severity":"error","filePath":"paddleocr/_api_client/_http.py","lineNumber":203,"sourceCode":"    def fetch_jsonl(self, url: str) -> list:\n        # Result URLs are often pre-signed object storage links.\n        try:\n            resp = requests.get(url, timeout=self._timeout)\n        except requests.Timeout as e:\n            raise RequestTimeoutError(f\"Request timed out: {e}\") from e\n        except requests.ConnectionError as e:\n            raise NetworkError(f\"Connection failed: {e}\") from e\n        try:\n            resp.raise_for_status()\n            lines = resp.text.strip().split(\"\\n\")\n            results = []\n            for line in lines:\n                line = line.strip()\n                if line:\n                    results.append(json.loads(line))\n            return results\n        except json.JSONDecodeError as e:\n            raise ResultParseError(f\"Malformed JSONL result payload: {e}\") from e\n\n    def close(self):\n        self._session.close()\n","sourceCodeStart":185,"sourceCodeEnd":207,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/paddleocr/_api_client/_http.py#L185-L207","documentation":"Raised as ResultParseError when the JSONL payload downloaded from the OCR job's result URL cannot be parsed. fetch_jsonl splits the response body into lines and calls json.loads on each non-empty line; any line that is not valid JSON triggers this error with the underlying JSONDecodeError chained as the cause.","triggerScenarios":"Calling the high-level OCR API (create job -> poll until done -> fetch results): the job reaches state 'done', the client downloads the JSONL from the result URL, but the body contains an HTML error page, a proxy login page, a truncated response, or non-JSON content on any single line.","commonSituations":"Result URL served through a corporate proxy or CDN that injects an error page; expired/mis-signed result URL returning a 200 with an error body; response truncated by a flaky connection; server-side format change where the endpoint starts returning a single JSON object with embedded newlines inside strings.","solutions":["Print or log the chained JSONDecodeError (e.original) and fetch the raw result URL with curl to inspect the actual body being returned","If a proxy/CDN is intercepting the URL, whitelist the result domain or bypass the proxy for it","If the body is a single JSON object rather than JSONL, your PaddleOCR server version may emit a different format — pin/align the client version with your server version","If parsing legitimately varies, download resp.text yourself and parse defensively instead of relying on fetch_jsonl"],"exampleFix":"# before\njsonl_data = client._http.fetch_jsonl(json_url)  # raises ResultParseError on bad body\n\n# after\nimport requests, json\nresp = requests.get(json_url, timeout=300)\nresp.raise_for_status()\njsonl_data = [json.loads(l) for l in resp.text.splitlines() if l.strip()]  # inspect/parse manually","handlingStrategy":"try-catch","validationCode":"import json\ndef valid_jsonl(text: str) -> bool:\n    return all(\n        json.loads(line) is not None\n        for line in text.splitlines() if line.strip()\n    )","typeGuard":"def is_ocr_line(obj) -> bool:\n    return isinstance(obj, dict) and isinstance(obj.get('result'), dict)","tryCatchPattern":"from paddleocr._api_client.errors import ResultParseError\ntry:\n    results = http.fetch_jsonl(json_url)\nexcept ResultParseError as e:\n    logger.error(\"bad payload from %s: %s\", json_url, e)\n    raise","preventionTips":["Log the raw response body the first time parsing fails so schema problems are diagnosable","Pin client and server versions together so the JSONL schema cannot drift","Route result downloads through the same network path used for API calls to avoid proxy interference"],"tags":["parsing","jsonl","api-client","ocr"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}