HKUDS/DeepTutor · error · MinerUError

PDF file not found: {pdf_path}

Error message

PDF file not found: {pdf_path}

What it means

parse_cloud requires an existing file; the given path does not resolve to a regular file.

Source

Thrown at deeptutor/services/parsing/engines/mineru/cloud.py:77

    timeout: float = DEFAULT_TIMEOUT_SECONDS,
    on_progress: Callable[[str], None] | None = None,
) -> Path:
    """Parse ``pdf_path`` via the MinerU cloud API; return the working dir.

    The working dir sits under ``output_base`` (named after the PDF stem) and
    holds the unzipped MinerU artifacts. ``on_progress`` (if given) receives a
    short status line whenever the polled task state / page count changes.
    Raises :class:`MinerUError` on any misconfiguration, API error, timeout,
    or extraction failure.
    """
    if not config.api_keys:
        raise MinerUError(
            "MinerU cloud mode is selected but no API token is configured. "
            "Add a token in Settings → MinerU, or switch to local mode."
        )
    pdf_path = Path(pdf_path)
    if not pdf_path.is_file():
        raise MinerUError(f"PDF file not found: {pdf_path}")

    base_url = config.api_base_url.rstrip("/")
    key_pool = KeyPool(config.api_keys)

    def report(message: str) -> None:
        if on_progress is None:
            return
        try:
            on_progress(message)
        except Exception:
            logger.debug("on_progress callback failed", exc_info=True)

    with httpx.Client(base_url=base_url, headers={"Accept": "application/json"}) as client:
        report(f"MinerU cloud: requesting upload slot for {pdf_path.name}")
        batch_id, upload_url = _request_upload(client, pdf_path, config, key_pool)
        size_mb = pdf_path.stat().st_size / (1024 * 1024)
        report(f"MinerU cloud: uploading {pdf_path.name} ({size_mb:.1f} MB)")
        _upload_file(pdf_path, upload_url)

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Check pdf_path.is_file() before calling and log the absolute path.
  2. Re-check for races where uploads are queued and files later removed.
  3. Pass absolute paths (Path(...).resolve()).

Example fix

# before
parse_cloud("docs/paper.pdf", ...)

# after
p = Path("docs/paper.pdf").resolve()
assert p.is_file(), p
parse_cloud(p, ...)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
p = Path(pdf_path).resolve()
assert p.is_file() and p.suffix.lower() == ".pdf", f"missing or non-PDF: {p}"

Try / catch

try:
    parse_cloud(p, ...)
except MinerUError as e:
    if e.args[0].startswith("PDF file not found"):
        relocate_or_reupload(p)

Prevention

When it happens

Trigger: Passing a wrong/relative path, a file deleted between scheduling and parsing, or a directory instead of a PDF.

Common situations: Temp-file cleanup races, path built from untrusted input, relative path resolved against a different CWD.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/4b800615ba0c4d21. Report an issue: GitHub.