{"record":{"id":"728e4d380a67f029","repo":"PaddlePaddle/PaddleOCR","slug":"destination-already-exists-target","errorCode":null,"errorMessage":"Destination already exists: ${target}","messagePattern":"Destination already exists: (.+?)","errorType":"exception","errorClass":"InvalidRequestError","httpStatus":null,"severity":"error","filePath":"api_sdk/typescript/src/client.ts","lineNumber":205,"sourceCode":"    let destinationStat;\n    try {\n      destinationStat = await stat(destination);\n    } catch {\n      throw new FileNotFoundError(destination);\n    }\n    if (!destinationStat.isDirectory()) {\n      throw new InvalidRequestError(`Destination must be an existing directory: ${destination}`);\n    }\n  }\n\n  private async requireWritableTarget(target: string, options: SaveResourceOptions): Promise<void> {\n    try {\n      await stat(target);\n    } catch {\n      return;\n    }\n    if (!options.overwrite) {\n      throw new InvalidRequestError(`Destination already exists: ${target}`);\n    }\n  }\n\n  private requireUniqueTargets(targets: string[], options: SaveResourceOptions): void {\n    if (options.overwrite) {\n      return;\n    }\n    const seen = new Set<string>();\n    for (const target of targets) {\n      if (seen.has(target)) {\n        throw new InvalidRequestError(`Destination already exists: ${target}`);\n      }\n      seen.add(target);\n    }\n  }\n\n  private async resolveDestination(url: URL, destination: string, options: SaveResourceOptions): Promise<string> {\n    let destinationStat;","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/api_sdk/typescript/src/client.ts#L187-L223","documentation":"Thrown by parse_batch_status in paddleocr/_api_client/_core.py:207 when an extractResult entry is an object but its 'jobId' is not a non-empty string. Every batch item must carry a jobId so the SDK can track each job individually. A missing/empty/null jobId in any single item fails the whole batch parse. ResponseFormatError.","triggerScenarios":"get_batch_status where any extractResult item lacks jobId, e.g. {\"state\": \"running\"} with no jobId, or jobId is null/empty/numeric.","commonSituations":"Server dropping jobId for failed or expunged jobs; schema drift; mock batch payloads missing required keys; proxy-modified JSON.","solutions":["Dump the batch response and identify which item lacks jobId","If those jobs were cancelled/deleted server-side, recreate the batch","Upgrade the SDK in case item schema changed","Fix mock servers to always include a non-empty string jobId per item"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def batch_items_have_job_ids(data: dict) -> bool:\n    items = data.get(\"extractResult\")\n    return isinstance(items, list) and all(\n        isinstance(i, dict) and isinstance(i.get(\"jobId\"), str) and i[\"jobId\"]\n        for i in items\n    )","tryCatchPattern":"from paddleocr._api_client.errors import ResponseFormatError\ntry:\n    batch = client.get_batch_status(batch_id)\nexcept ResponseFormatError as e:\n    if \"jobId\" in str(e):\n        logger.error(\"One batch item lacks jobId; batch=%s\", batch_id)\n    raise","preventionTips":["Include jobId in every mock batch item","Log the batchId on failure so the offending server payload can be retrieved manually"],"tags":["api","response-format","batch","job","schema"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}