PaddlePaddle/PaddleOCR · error · JobFailedError

Job {job_id} failed: {error_msg}

Error message

Job {job_id} failed: {error_msg}

What it means

JobFailedError raised when the job status payload reports state == 'failed'. The server-side pipeline rejected or crashed on the job; the message embeds the job_id and the server's errorMsg field (or 'Unknown error' if the payload omitted errorMsg). This is a terminal state — no amount of continued polling will change it.

Source

Thrown at paddleocr/_api_client/_poller.py:79

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

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

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

            if state == "done":
                json_url = validate_result_json_url(data)
                jsonl_data = 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 - time.monotonic()
            if remaining <= 0:
                raise PollTimeoutError(job_id, time.monotonic() - start)

            time.sleep(min(interval, remaining))
            interval = min(interval * self._multiplier, self._max_interval)

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

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


def parse_ocr_result(job_id: str, jsonl_data: list) -> OCRResult:

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Read the errorMsg embedded in the exception — it comes straight from the server and names the root cause
  2. Reproduce with the smallest input that fails; if a specific file always fails, validate/re-save that file (e.g. re-export the PDF) before resubmitting
  3. If errorMsg is 'Unknown error', call get_status(job_id) to inspect the full raw status payload for extra fields
  4. If failures are intermittent or input-independent, check server logs/capacity rather than the client

Example fix

# before
jsonl, raw = poller.poll_until_done(job_id)  # JobFailedError bubbles up raw

# after
try:
    jsonl, raw = poller.poll_until_done(job_id)
except JobFailedError as e:
    status = poller.get_status(job_id)
    logger.error("job %s failed: %s raw=%s", e.job_id, e, status.raw)
Defensive patterns

Strategy: try-catch

Validate before calling

# validate input before submitting to reduce server-side failures
def submittable(path) -> bool:
    return path.stat().st_size > 0 and path.suffix.lower() in {'.pdf', '.png', '.jpg', '.jpeg', '.bmp', '.tiff'}

Try / catch

from paddleocr._api_client.errors import JobFailedError
try:
    jsonl, raw = poller.poll_until_done(job_id)
except JobFailedError as e:
    logger.error("server failed job %s: %s", e.job_id, e)
    raise

Prevention

When it happens

Trigger: poll_until_done() observes state 'failed' for a submitted OCR/document-parsing job. Typical server reasons: unsupported or corrupt input file, file larger than the server limit, OCR backend crash, invalid parameters stored with the job, or quota/billing rejection.

Common situations: Uploading a password-protected or zero-byte PDF; sending an image format the server cannot decode; server OOM during inference on very large pages; API plan limits exceeded; server version regression marking jobs failed intermittently.

Related errors


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