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
- Read the errorMsg embedded in the exception — it comes straight from the server and names the root cause
- 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
- If errorMsg is 'Unknown error', call get_status(job_id) to inspect the full raw status payload for extra fields
- 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
- Pre-check files: non-zero size, supported format, not password-protected PDFs
- Keep the job_id and resubmit only the failed job, not the whole batch
- Record errorMsg strings to spot recurring server-side causes
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
- Timed out after {elapsed:.1f}s waiting for job {job_id}
- Document parsing result item is missing result.layoutParsing
- Document parsing result page is missing markdown.text.
- Job ${job.jobId} is a ${job.task} job, not a ${expectedTask}
- Job ${jobId} failed: ${errorMsg}
AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14).
Data as JSON: /api/errors/c0cc05e64ba52309.
Report an issue: GitHub.