opendatalab/MinerU · error · TimeoutError

PDF image rendering timeout after {timeout}s for pages {star

Error message

PDF image rendering timeout after {timeout}s for pages {start_page_id + 1}-{end_page_id + 1}

What it means

TimeoutError raised by MineRU's parallel PDF page renderer when the executor futures that render page ranges to images do not all complete within the configured timeout (wait(..., timeout=timeout, return_when=ALL_COMPLETED) returns not_done futures). Rendering is split into page-range chunks submitted to a process/thread pool; the message reports the overall timeout and the 1-based page span requested. The executor is flagged for recycling (recycle_executor = True) because a worker is presumed stuck, and remaining futures are abandoned.

Source

Thrown at mineru/utils/pdf_image_tools.py:316

        futures = []
        future_to_range = {}
        for range_start, range_end in page_ranges:
            future = _submit_pdf_render_task(
                executor,
                _load_images_from_pdf_worker,
                pdf_bytes,
                dpi,
                range_start,
                range_end,
                image_type,
            )
            futures.append(future)
            future_to_range[future] = range_start

        _, not_done = wait(futures, timeout=timeout, return_when=ALL_COMPLETED)
        if not_done:
            recycle_executor = True
            raise TimeoutError(
                f"PDF image rendering timeout after {timeout}s "
                f"for pages {start_page_id + 1}-{end_page_id + 1}"
            )

        all_results = []
        for future in futures:
            range_start = future_to_range[future]
            images_list = future.result()
            collected_image_lists.append(images_list)
            all_results.append((range_start, images_list))

        all_results.sort(key=lambda x: x[0])
        images_list = []
        for _, imgs in all_results:
            images_list.extend(imgs)

        collected_image_lists.clear()
        return images_list

View on GitHub (pinned to 4fe4bde114)

Solutions

  1. Raise the timeout parameter so it scales with page count and DPI (e.g. 30s per 50 pages as a starting heuristic), since the budget covers all ranges submitted together.
  2. Reduce per-page cost: lower DPI, process the document in smaller end_page_id/start_page_id chunks instead of the whole file at once.
  3. Give the process real resources: increase container CPU/memory limits, avoid oversubscribing the executor with unrelated work.
  4. If it recurs deterministically on one file, that PDF is likely corrupt/pathological — try re-saving it with qpdf or Ghostscript, or render that page range separately to isolate the culprit page.
  5. Retry once on a fresh process: the executor-recycling flag exists because a stuck worker often clears after a restart.

Example fix

# before
images = pdf_image_tools...render(timeout=60)  # 500-page scanned book -> TimeoutError

# after
for start in range(0, n_pages, 50):
    images += render_range(start, min(start + 50, n_pages), dpi=150, timeout=120)
Defensive patterns

Strategy: retry

Validate before calling

n_pages = get_page_count(pdf_bytes)
timeout = max(60, n_pages * 2)  # scale budget with document size
dpi = 150 if n_pages > 200 else 200  # reduce cost for big docs

Type guard

def render_budget_ok(n_pages: int, dpi: int, timeout: int) -> bool:
    # rough heuristic: ~0.5-2s per page at 150-200 dpi with healthy workers
    return timeout >= n_pages * 1.5 * (dpi / 150.0)

Try / catch

for attempt in range(2):
    try:
        images = render_pages(pdf_bytes, start, end, dpi=dpi, timeout=timeout)
        break
    except TimeoutError:
        if attempt == 1:
            raise  # executor is recycled; retry once on a fresh one, then surface
        timeout *= 2

Prevention

When it happens

Trigger: Calling the PDF-to-image utility (mineru.utils.pdf_image_tools) with a very large or pathological PDF (hundreds/thousands of pages, huge page sizes, complex vector graphics) and the default or a low timeout; or with an executor whose workers are starved (CPU-bound competing processes, very low memory causing swapping, PyMuPDF deadlocks in forked workers).

Common situations: Batch servers processing scanned books at high DPI; containers with CPU limits where each worker gets a fraction of a core; memory exhaustion making rendering orders of magnitude slower; a hung worker from a known fork-after-import issue in the renderer.

Understand the failure class

Related errors


AI-assisted analysis of opendatalab/MinerU@4fe4bde114 (2026-08-14). Data as JSON: /api/errors/530a469a85daecab. Report an issue: GitHub.