PaddlePaddle/PaddleOCR · error · NetworkError

Failed to download resource: {e}

Error message

Failed to download resource: {e}

What it means

NetworkError raised when response.raise_for_status() fails after a successful download connection: the server answered with an HTTP error status (4xx/5xx). Unlike 190, the connection worked — the resource request itself was rejected.

Source

Thrown at paddleocr/_api_client/_resources.py:57

    parsed_url = urlparse(resource_url)
    if parsed_url.scheme not in ("http", "https") or not parsed_url.netloc:
        raise InvalidRequestError(f"Invalid resource URL: {resource_url}")

    target = _resolve_destination(parsed_url.path, destination, filename)
    _require_writable_target(target, overwrite)

    try:
        response = requests.get(resource_url, timeout=timeout)
    except requests.Timeout as e:
        raise RequestTimeoutError(f"Request timed out: {e}") from e
    except requests.ConnectionError as e:
        raise NetworkError(f"Connection failed: {e}") from e

    try:
        response.raise_for_status()
    except requests.RequestException as e:
        raise NetworkError(f"Failed to download resource: {e}") from e

    _atomic_write(target, response.content, overwrite)
    return str(target)


def save_ocr_result_resources(
    result: OCRResult,
    destination: str,
    *,
    overwrite: bool = False,
    timeout: float = 300.0,
) -> List[str]:
    if result is None:
        raise InvalidRequestError("OCR result is required.")
    dest_dir = _require_existing_directory(destination)
    saved_paths = []
    for index, page in enumerate(result.pages):
        if not page.ocr_image_url:

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Re-create the job (or re-poll it) to obtain fresh result URLs — expired signatures are the most common cause
  2. Check the status code in the chained exception to distinguish 403/404 (expired/gone — must resubmit) from 5xx (retry later)
  3. Retry with backoff for 5xx statuses
  4. Ensure you download resources promptly after job completion, within the provider's retention window

Example fix

# before
result = client.ocr(...)  # much later:
save_resource(result.pages[0].ocr_image_url, dest)  # expired URL -> 403

# after
result = client.ocr(...)  # download immediately after job completes
save_ocr_result_resources(result, dest_dir, timeout=300)
Defensive patterns

Strategy: retry

Validate before calling

r = requests.head(url, timeout=30)
if r.status_code in (401, 403, 404):
    raise RuntimeError('result URL expired; resubmit the job')

Try / catch

try:
    save_resource(url, dest)
except NetworkError as e:
    code = e.__cause__.response.status_code if getattr(e.__cause__, 'response', None) else None
    if code and 500 <= code < 600:
        time.sleep(30); save_resource(url, dest)  # retry 5xx only
    else:
        raise  # 4xx: URL expired/gone, resubmit job

Prevention

When it happens

Trigger: save_resource hitting an expired signed result URL (403/404 from object storage), a result URL invalidated because the job's retention window elapsed, an auth-protected bucket returning 401, or the storage backend returning 5xx under load.

Common situations: Fetching OCR result images hours/days after job completion once presigned URLs expire; re-running an old job's saved URLs; bucket permission changes; transient 502/503 from the CDN in front of result storage.

Related errors


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