{"record":{"id":"c53540ad3f16b3e7","repo":"PaddlePaddle/PaddleOCR","slug":"malformed-jsonl-result-payload-e","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/_async_http.py","lineNumber":163,"sourceCode":"            return await self._response_data(resp)\n\n    async def get_batch_status(self, batch_id: str) -> Dict[str, Any]:\n        await self._ensure_session()\n        async with self._session.get(f\"{self._jobs_url}/batch/{batch_id}\") as resp:\n            await self._raise_for_response(resp)\n            return await self._response_data(resp)\n\n    async def fetch_jsonl(self, url: str) -> list:\n        timeout = aiohttp.ClientTimeout(total=self._timeout)\n        async with aiohttp.ClientSession(timeout=timeout) as bare_session:\n            async with bare_session.get(url) as resp:\n                await self._raise_for_response(resp)\n                text = await resp.text()\n                try:\n                    lines = text.strip().split(\"\\n\")\n                    return [json.loads(line) for line in lines if line.strip()]\n                except json.JSONDecodeError as e:\n                    raise ResultParseError(\n                        f\"Malformed JSONL result payload: {e}\"\n                    ) from e\n\n    async def _raise_for_response(self, resp) -> None:\n        if 200 <= resp.status < 300:\n            return\n        try:\n            body = await resp.json()\n            msg = (\n                extract_api_message_from_payload(body)\n                if isinstance(body, dict)\n                else None\n            )\n            if not msg:\n                msg = await resp.text()\n        except Exception:\n            msg = await resp.text()\n        raise_for_status(resp.status, msg)","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/paddleocr/_api_client/_async_http.py#L145-L181","documentation":"ResultParseError from fetch_jsonl in the async API client: the poller downloads the job's result JSONL URL, splits it into lines, and json.loads each non-empty line; any line that is not valid JSON raises with the underlying JSONDecodeError chained. This indicates the downloaded result payload is not the expected line-delimited JSON.","triggerScenarios":"The result URL returns an HTML error page (auth expiry, S3 error XML) with a 200 status; a partially downloaded/truncated file; the endpoint switching format (e.g. a single JSON object or CSV) so one line fails to parse.","commonSituations":"Pre-signed result URLs expiring between job completion and fetch; proxies injecting content; API version changes altering the result format.","solutions":["Fetch the URL manually (curl) and inspect the first lines — HTML/XML means an auth or expiry problem, not corruption.","Retry the poll/parse once; transient truncation or proxy pages often clear.","Upgrade the paddleocr API client if the service changed its result format.","Ensure the result URL is fetched promptly after job completion before any expiry window closes."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import json, urllib.request\n\ndef jsonl_url_fetchable(url: str) -> bool:\n    try:\n        with urllib.request.urlopen(url, timeout=30) as r:\n            first = r.readline().decode()\n            json.loads(first)\n            return True\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"from paddleocr._api_client.errors import ResultParseError\n\nfor attempt in range(2):\n    try:\n        data = await http.fetch_jsonl(url)\n        break\n    except ResultParseError:\n        if attempt == 1:\n            raise  # persistent: URL likely returns an error page, not JSONL\n        await asyncio.sleep(2)","preventionTips":["Fetch result URLs promptly after job completion, before pre-signed links expire.","On parse failure, curl the URL once to distinguish an HTML error page from real corruption.","Pin the api-client version matching the service's result format."],"tags":["python","asyncio","jsonl","parse","api-client"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}