PaddlePaddle/PaddleOCR · error · JobFailedError

Job {job_id} failed: {error_msg}

Error message

Job {job_id} failed: {error_msg}

What it means

Raised as JobFailedError by the async poller when a submitted job's state transitions to 'failed' on the service side. The message embeds the job_id and the service-provided errorMsg (or 'Unknown error' when the payload omits it). This means the request was accepted but processing failed downstream, so retrying with identical inputs often fails again.

Source

Thrown at paddleocr/_api_client/_async_poller.py:72

        start = loop.time()
        deadline = start + self._max_wait_time

        while True:
            now = loop.time()
            if now >= deadline:
                raise PollTimeoutError(job_id, now - start)

            data = await self._http.get_job_status(job_id)
            state = validate_state(data)

            if state == "done":
                json_url = validate_result_json_url(data)
                jsonl_data = await self._http.fetch_jsonl(json_url)
                return jsonl_data, data

            if state == "failed":
                error_msg = data.get("errorMsg", "Unknown error")
                raise JobFailedError(job_id, error_msg)

            remaining = deadline - loop.time()
            if remaining <= 0:
                raise PollTimeoutError(job_id, loop.time() - start)
            await asyncio.sleep(min(interval, remaining))
            interval = min(interval * self._multiplier, self._max_interval)

    async def get_status(self, job_id: str) -> JobStatus:
        data = await self._http.get_job_status(job_id)
        return job_status_from_data(job_id, data)

    async def get_batch_status(self, batch_id: str) -> BatchStatus:
        data = await self._http.get_batch_status(batch_id)
        return parse_batch_status(batch_id, data)

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Read the errorMsg embedded in the exception to identify the service-side reason before changing anything.
  2. Verify the input file: open the file_url/file_path locally, confirm it is a supported format and not truncated.
  3. Check that the model and options match the input (e.g. document-parsing model for PDFs, OCR model for images).
  4. Retry once with a fresh job after fixing the input; if errorMsg indicates a transient internal error, recreate the job with the same input.
  5. If failures persist, capture job_id and errorMsg and report to PaddleOCR AI Studio support.

Example fix

// before
result = await client.ocr(file_path="doc.pdf")  # raises JobFailedError

// after
try:
    result = await client.ocr(file_path="doc.pdf")
except JobFailedError as e:
    print(f"job {e.job_id} failed: {e.message}")
    # inspect input file / model choice, then resubmit
Defensive patterns

Strategy: try-catch

Try / catch

from paddleocr._api_client.errors import JobFailedError
try:
    result = await client.ocr(file_path=path)
except JobFailedError as e:
    # e.job_id and str(e) carry the service-side reason
    log.warning("job %s failed: %s", e.job_id, e)
    raise

Prevention

When it happens

Trigger: Calling an async API method that polls to completion (e.g. create OCR/document-parsing job then wait) where get_job_status() eventually returns state == 'failed'. The payload's errorMsg field supplies the reason; if absent, 'Unknown error' is used.

Common situations: Corrupt or unreadable input file at the given file_url, unsupported file format or oversized document, model mismatch for the input type, or transient service-side failures during extraction. Also seen when the uploaded URL expires before the service fetches it.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/dd89a7be8eada5ff. Report an issue: GitHub.