docling-project/docling · error · ArtifactDownloadError
Artifact download failed with HTTP {response.status_code}.
Error message
Artifact download failed with HTTP {response.status_code}. What it means
Raised as ArtifactDownloadError by the synchronous _download_artifact_bytes when the artifact server answers with a non-200, non-redirect status (403 expired presigned URL, 404 deleted object, 500, etc.). Each redirect hop is re-validated and followed manually; any final status other than 200 fails. Normally converted into a FAILURE ConversionResult by the materialization path.
Source
Thrown at docling/service_client/client.py:1899
"""Download an external presigned artifact safely (sync).
Uses a dedicated client so the service ``X-Api-Key`` header is never sent
to the (external) artifact storage endpoint, validates every hop against
the SSRF guard, and enforces a streamed size cap. Redirects are followed
manually so each target can be re-validated.
"""
timeout = httpx.Timeout(self._artifact_download_timeout)
try:
with httpx.Client(timeout=timeout, follow_redirects=False) as client:
url = uri
for _ in range(MAX_ARTIFACT_DOWNLOAD_REDIRECTS + 1):
self._validate_artifact_url(url)
with client.stream("GET", url) as response:
if response.is_redirect:
url = self._next_redirect_url(url, response)
continue
if response.status_code != 200:
raise ArtifactDownloadError(
"Artifact download failed with HTTP "
f"{response.status_code}."
)
chunks: list[bytes] = []
total = 0
for chunk in response.iter_bytes():
total += len(chunk)
self._check_artifact_size(total)
chunks.append(chunk)
return b"".join(chunks)
raise ArtifactDownloadError(
"Too many redirects while downloading artifact."
)
except httpx.HTTPError as exc:
raise ArtifactDownloadError(f"Artifact download failed: {exc}") from exc
async def _download_artifact_bytes_async(self, uri: str) -> bytes:
timeout = httpx.Timeout(self._artifact_download_timeout)View on GitHub (pinned to 61d76f1ff3)
Solutions
- Retry the conversion — expired presigned URLs are transient and a new task gets a fresh URL
- Increase artifact_download_timeout and check network reachability to the object-store host if status is 5xx
- Check object-store lifecycle/retention settings if 404s recur (artifacts cleaned before retrieval)
Defensive patterns
Strategy: retry
Type guard
def is_artifact_download_error(exc: BaseException) -> bool:
return isinstance(exc, ArtifactDownloadError) Try / catch
if res.status == ConversionStatus.FAILURE:
if any('HTTP 403' in (e.error_message or '') for e in res.errors):
res = retry_conversion(source) # fresh presigned URL Prevention
- Retry conversions on 403 — presigned URL expiry is transient
- Keep queue waits short enough that URLs do not expire before download
When it happens
Trigger: convert()/convert_all() materializing an artifact whose presigned URL has expired (S3/Xpiry headers), the object was deleted, or the endpoint returns 4xx/5xx.
Common situations: Long queue times so presigned URLs expire before download; clock skew; object lifecycle rules deleting artifacts; load balancer errors on the artifact host.
Related errors
- Too many redirects while downloading artifact.
- Artifact download failed: {exc}
- Refusing to download artifact from a non-public URL: {url}.
- Artifact download redirect is missing a Location header.
- URL must contain a valid hostname
AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14).
Data as JSON: /api/errors/10a43f2ea44a2881.
Report an issue: GitHub.