{"record":{"id":"12acbc83095b26f5","repo":"PaddlePaddle/PaddleOCR","slug":"invalid-resource-url-resourceurl","errorCode":null,"errorMessage":"Invalid resource URL: ${resourceUrl}","messagePattern":"Invalid resource URL: (.+?)","errorType":"exception","errorClass":"InvalidRequestError","httpStatus":null,"severity":"error","filePath":"api_sdk/typescript/src/client.ts","lineNumber":131,"sourceCode":"  }\n\n  async saveDocumentParsingResultResources(\n    result: DocParsingResult,\n    destination: string,\n    options: SaveResourceOptions = {},\n  ): Promise<string[]> {\n    return this.saveResultResources(result, destination, options);\n  }\n\n  private async saveResourceUrl(resourceUrl: string, destination: string, options: SaveResourceOptions): Promise<string> {\n    if (!resourceUrl) {\n      throw new InvalidRequestError(\"resourceUrl is required.\");\n    }\n    let url: URL;\n    try {\n      url = new URL(resourceUrl);\n    } catch (error) {\n      throw new InvalidRequestError(`Invalid resource URL: ${resourceUrl}`, { cause: error });\n    }\n    const target = await this.resolveDestination(url, destination, options);\n    const content = await this.http.fetchResource(resourceUrl);\n    await writeFile(target, Buffer.from(content), { flag: options.overwrite ? \"w\" : \"wx\" });\n    return target;\n  }\n\n  private async saveResultResources(\n    result: OCRResult | DocParsingResult,\n    destination: string,\n    options: SaveResourceOptions,\n  ): Promise<string[]> {\n    await this.requireExistingDirectory(destination);\n    const plans = this.collectResultResourcePlans(result);\n    const targets = plans.map((plan) => join(destination, plan.filename));\n    for (const target of targets) {\n      await this.requireWritableTarget(target, options);\n    }","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/api_sdk/typescript/src/client.ts#L113-L149","documentation":"Thrown by validate_result_json_url in paddleocr/_api_client/_core.py:189 when the done job's resultUrl object exists but its 'jsonUrl' field is not a non-empty string. jsonUrl is the pre-signed URL the SDK downloads JSONL results from; an empty/missing/null value makes download impossible. This is a ResponseFormatError indicating a malformed server response for a completed job.","triggerScenarios":"Retrieving results of a done job where data.resultUrl exists but resultUrl.jsonUrl is absent, empty, null, or a non-string (e.g. a list of URLs).","commonSituations":"Result artifacts not yet generated when the job flipped to done; pre-signed URL generation failing server-side; schema drift in the API; truncated response from a proxy.","solutions":["Wait a few seconds and poll job status again — jsonUrl may appear once artifact generation settles","Dump the raw status response to confirm resultUrl contents","If jsonUrl is consistently absent for done jobs, upgrade the SDK and/or report to PaddleOCR — the server response is malformed","As a workaround, check whether resultUrl carries an alternative field (e.g. a zip URL) and fetch results manually"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"status = client.get_job_status(job_id)\nru = status.get(\"resultUrl\")\nif isinstance(ru, dict) and not (isinstance(ru.get(\"jsonUrl\"), str) and ru[\"jsonUrl\"]:\n    print(\"jsonUrl not ready\")","typeGuard":"def has_json_url(data: dict) -> bool:\n    ru = data.get(\"resultUrl\")\n    return isinstance(ru, dict) and isinstance(ru.get(\"jsonUrl\"), str) and bool(ru[\"jsonUrl\"])","tryCatchPattern":"from paddleocr._api_client.errors import ResponseFormatError\ntry:\n    result = client.get_result(job_id)\nexcept ResponseFormatError as e:\n    if \"jsonUrl\" in str(e):\n        time.sleep(5)\n        result = client.get_result(job_id)","preventionTips":["Treat a just-flipped 'done' state as eventually consistent — retry result fetch once after a delay","Monitor for schema drift on resultUrl in integration tests"],"tags":["api","response-format","result","presigned-url"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}