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
- Re-create the job (or re-poll it) to obtain fresh result URLs — expired signatures are the most common cause
- Check the status code in the chained exception to distinguish 403/404 (expired/gone — must resubmit) from 5xx (retry later)
- Retry with backoff for 5xx statuses
- 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
- Download result artifacts immediately after job completion, before presigned URLs expire
- Persist enough state (file hashes) to re-create jobs instead of reusing stale URLs
- Distinguish 4xx (permanent) from 5xx (retryable) before retrying
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
- Downloading from {} failed with code {}!
- Unsafe resource filename: ${key}
- resource_url is required.
- Invalid resource URL: {resource_url}
- Request timed out: {e}
AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14).
Data as JSON: /api/errors/9fb57032186e0952.
Report an issue: GitHub.