docling-project/docling · error · ServiceUnavailableError
Service returned HTTP {response.status_code} after retries.
Error message
Service returned HTTP {response.status_code} after retries. What it means
The mirror of error 358 for responses that DO carry a Retry-After header: the sync client honors the header's delay and retries, but once attempt >= max_retries it stops and raises ServiceUnavailableError stating the service returned that HTTP status after all retries. Typical for 429 rate limiting or 503 load shedding where the server keeps asking the client to come back later.
Source
Thrown at docling/service_client/client.py:611
return None, self._exponential_backoff_delay(attempt)
raise ServiceUnavailableError(
error_message,
status_code=response.status_code,
detail=self._http_error_detail(response),
)
def _retry_with_retry_after_header(
self,
response: httpx.Response,
attempt: int,
max_retries: int,
) -> tuple[httpx.Response | None, float]:
retry_after_delay = self._retry_after_delay_seconds(response)
if retry_after_delay is None:
return response, 0.0
if attempt < max_retries:
return None, retry_after_delay
raise ServiceUnavailableError(
f"Service returned HTTP {response.status_code} after retries.",
status_code=response.status_code,
detail=self._http_error_detail(response),
)
def _exponential_backoff_delay(self, attempt: int) -> float:
return HTTP_RETRY_BACKOFF_BASE_SECONDS * (2**attempt)
def _transport_retry_delay(
self,
*,
method: str,
exc: httpx.HTTPError,
attempt: int,
max_retries: int,
) -> float | None:
method_name = method.upper()
if (View on GitHub (pinned to 61d76f1ff3)
Solutions
- Reduce request concurrency/rate on the client side to stay under limits.
- Raise http_retries so the client survives longer throttle windows honoring Retry-After.
- Catch ServiceUnavailableError, wait, and resubmit the remaining work later.
- Scale the service or negotiate higher limits if throttling is steady-state.
Example fix
# before
client = DocumentConverterClient(url, max_concurrency=64)
results = [client.convert_file(f) for f in many_files] # 429s exhaust retries
# after
client = DocumentConverterClient(url, max_concurrency=4, http_retries=8)
from docling.service_client.exceptions import ServiceUnavailableError
import time
for f in many_files:
for attempt in range(3):
try:
results.append(client.convert_file(f)); break
except ServiceUnavailableError:
time.sleep(30) Defensive patterns
Strategy: retry
Try / catch
from docling.service_client.exceptions import ServiceUnavailableError
import time
for attempt in range(5):
try:
result = client.convert_file(f)
break
except ServiceUnavailableError as e:
if e.status_code not in (429, 503):
raise
time.sleep(min(60, 5 * 2 ** attempt)) Prevention
- Keep client concurrency low enough to avoid 429s entirely.
- Honor Retry-After semantics: back off longer, don't just retry faster.
- Raise http_retries when the service throttles for extended windows.
When it happens
Trigger: Sustained 429 rate limiting with Retry-After exceeding the retry budget; service shedding load with 503+Retry-After during peak; too many concurrent client requests against a small docling-serve instance.
Common situations: Batch conversion tripping rate limits; shared service instances throttling per-client; retry budget (default few attempts) shorter than the throttle window.
Related errors
- Service request failed after retry loop.
- {error_message}
- Service transport request failed.
- Service transport request failed after retries.
- Service transport request failed.
AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14).
Data as JSON: /api/errors/d3537274dba2f5b7.
Report an issue: GitHub.