HKUDS/DeepTutor · error · MinerUError

Failed to upload PDF to MinerU: {exc}

Error message

Failed to upload PDF to MinerU: {exc}

What it means

The signed upload URL was obtained, but the HTTP PUT of the PDF bytes failed (network error, DNS, TLS, timeout, or non-2xx status via raise_for_status).

Source

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

    file_urls = data.get("file_urls") or []
    if not batch_id or not isinstance(file_urls, list) or not file_urls:
        raise MinerUError("MinerU API did not return an upload URL (missing batch_id/file_urls).")
    return batch_id, str(file_urls[0])


def _upload_file(pdf_path: Path, upload_url: str) -> None:
    """PUT the PDF bytes to the signed URL.

    The signed URL carries its own auth; per MinerU's docs we must NOT send an
    ``Authorization`` or ``Content-Type`` header (a stray Content-Type breaks
    the OSS signature).
    """
    data = pdf_path.read_bytes()
    try:
        response = httpx.put(upload_url, content=data, timeout=_UPLOAD_TIMEOUT_SECONDS)
        response.raise_for_status()
    except httpx.HTTPError as exc:
        raise MinerUError(f"Failed to upload PDF to MinerU: {exc}") from exc


def _poll_for_zip(
    client: httpx.Client,
    batch_id: str,
    file_name: str,
    *,
    key_pool: KeyPool,
    poll_interval: float,
    timeout: float,
    on_progress: Callable[[str], None] | None = None,
) -> str:
    """Poll the batch results until our file is ``done``; return full_zip_url."""
    deadline = time.monotonic() + timeout
    last_state = ""
    last_report = ""
    while True:
        payload = _get_json(client, f"/api/v4/extract-results/batch/{batch_id}", key_pool)

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Retry the whole parse (a fresh signed URL is requested each attempt).
  2. Check network/proxy access to the storage host in the upload URL.
  3. Reduce PDF size or check the timeout budget for large files.
  4. Verify system clock — signed URLs are time-sensitive.

Example fix

# before
res = parse_pdf_to_workdir(pdf, wd, cfg)

# after
for attempt in range(3):
    try:
        res = parse_pdf_to_workdir(pdf, wd, cfg); break
    except MinerUError as e:
        if "upload" not in str(e).lower() or attempt == 2: raise
        time.sleep(2 ** attempt)
Defensive patterns

Strategy: retry

Validate before calling

def uploadable(pdf: Path) -> bool:
    return pdf.is_file() and pdf.stat().st_size < 200 * 1024 * 1024

Try / catch

for i in range(3):
    try:
        parse_pdf_to_workdir(pdf, wd, cfg); break
    except MinerUError as e:
        if "upload PDF" not in str(e) or i == 2: raise
        time.sleep(2 ** i)

Prevention

When it happens

Trigger: httpx.put(upload_url, ...) raising httpx.HTTPError — expired signed URL, network drop, proxy blocking the object-store host, or 4xx/5xx from storage.

Common situations: Long delay between requesting the batch and uploading (URL expiry), corporate proxies/firewalls, large PDFs exceeding an upload limit or timing out (_UPLOAD_TIMEOUT_SECONDS).

Related errors


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