{"record":{"id":"3bbf24969d58589a","repo":"PaddlePaddle/PaddleOCR","slug":"failed-to-parse-jsonl-result-payload","errorCode":null,"errorMessage":"Failed to parse JSONL result payload.","messagePattern":"Failed to parse JSONL result payload\\.","errorType":"exception","errorClass":"ResultParseError","httpStatus":null,"severity":"error","filePath":"api_sdk/typescript/src/internal/http.ts","lineNumber":146,"sourceCode":"      `${this.jobsUrl}/batch/${encodeURIComponent(batchId)}`,\n      { method: \"GET\" },\n      signal,\n      true,\n      timeoutMs,\n    );\n  }\n\n  async fetchJsonl(url: string, signal?: AbortSignal, timeoutMs?: number): Promise<unknown[]> {\n    const resp = await this.fetch(url, { method: \"GET\" }, signal, false, timeoutMs);\n    const text = await resp.text();\n    try {\n      return text\n        .trim()\n        .split(\"\\n\")\n        .filter((line) => line.trim())\n        .map((line) => JSON.parse(line) as unknown);\n    } catch (error) {\n      throw new ResultParseError(\"Failed to parse JSONL result payload.\", { cause: error });\n    }\n  }\n\n  async fetchResource(url: string, signal?: AbortSignal, timeoutMs?: number): Promise<ArrayBuffer> {\n    const resp = await this.fetch(url, { method: \"GET\" }, signal, false, timeoutMs);\n    return resp.arrayBuffer();\n  }\n\n  private async fetchJson<T>(\n    url: string,\n    init: RequestInit,\n    signal?: AbortSignal,\n    withAuth: boolean = true,\n    timeoutMs?: number,\n  ): Promise<T> {\n    const resp = await this.fetch(url, init, signal, withAuth, timeoutMs);\n    let payload: APIResponse<T>;\n    try {","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/api_sdk/typescript/src/internal/http.ts#L128-L164","documentation":"ResultParseError is thrown by fetchJsonl() when the result payload downloaded from the job's result URL cannot be parsed as JSON Lines: the body is split on newlines and every non-empty line must JSON.parse successfully. If any single line is malformed, the whole fetch fails with the original parse error attached as `cause`. This indicates the server-side result artifact is not valid JSONL, not that your code is wrong.","triggerScenarios":"Awaiting job completion (e.g. via the poller) which then calls fetchJsonl(resultJsonUrl) on a done job, and the downloaded result contains a truncated or corrupted line — e.g. a line break inside a JSON string value, a partially written result file, an HTML error page from a CDN, or a truncated body caused by a network interruption mid-download.","commonSituations":"Result files whose text fields contain embedded raw newlines (multi-page OCR text); a proxy/CDN serving a cached 200 HTML page instead of the JSONL; very large results truncated in transit; API version drift changing the artifact format.","solutions":["Inspect the raw payload: fetch the result URL manually with curl and check each line with a JSONL validator to find the offending line number","Retry the operation — a truncated or partially-written server artifact is often transient; a fresh job usually produces a valid file","Check error.cause for the underlying SyntaxError, which includes the exact character position of the malformed JSON","If the result URL is served through a proxy, bypass it or verify it is not mangling the body (gzip, ETag, HTML error pages)"],"exampleFix":"try {\n  const result = await client.extractFile(\"PP-StructureV3\", filePath, {});\n} catch (e) {\n  if (e instanceof ResultParseError) {\n    console.error(\"JSONL line failed:\", e.cause); // SyntaxError with position\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":"function isLikelyJsonl(text: string): boolean {\n  const lines = text.trim().split(\"\\n\").filter((l) => l.trim());\n  return lines.length > 0 && lines.every((l) => {\n    try { JSON.parse(l); return true; } catch { return false; }\n  });\n}","typeGuard":"function isJsonlPayload(v: unknown): v is unknown[] {\n  return Array.isArray(v);\n}","tryCatchPattern":"try {\n  const result = await poller.waitForResult(jobId);\n} catch (e) {\n  if (e instanceof ResultParseError) {\n    if (e.cause instanceof SyntaxError) {\n      // artifact corruption — retry the job once, then report\n      return retryJob(jobId);\n    }\n  }\n  throw e;\n}","preventionTips":["Treat ResultParseError as transient first: re-submit and re-download before debugging","Log e.cause (SyntaxError position) to identify which JSONL line is malformed","Verify no proxy sits between you and the result storage host if errors persist"],"tags":["parsing","jsonl","results","typescript"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}