docling-project/docling · error · ServiceUnavailableError

{error_message}

Error message

{error_message}

What it means

In the sync client's retry handling, _retry_with_exponential_backoff is called for retryable HTTP statuses without a Retry-After header. When attempt >= max_retries it gives up and raises ServiceUnavailableError with the caller-provided error_message (which names the failing operation) plus status code and response detail. It marks definitive exhaustion of the exponential backoff budget.

Source

Thrown at docling/service_client/client.py:594

            )
        if response.status_code in {429, 503}:
            return self._retry_with_retry_after_header(
                response=response,
                attempt=attempt,
                max_retries=max_retries,
            )
        return response, 0.0

    def _retry_with_exponential_backoff(
        self,
        response: httpx.Response,
        attempt: int,
        max_retries: int,
        error_message: str,
    ) -> tuple[httpx.Response | None, float]:
        if attempt < max_retries:
            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.",

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Check the service logs for the underlying 5xx cause (often one problematic document).
  2. Increase http_retries so transient 5xx bursts are absorbed.
  3. Isolate and retry the failing request separately; skip the poison document in batch runs.
  4. If errors are deterministic, the document or options may trigger a server bug — report upstream with the detail payload.

Example fix

# before
client = DocumentConverterClient(url)  # default retries
for f in files:
    client.convert_file(f)  # ServiceUnavailableError on server 500s

# after
client = DocumentConverterClient(url, http_retries=5)
for f in files:
    try:
        client.convert_file(f)
    except ServiceUnavailableError as e:
        log.error('skipping %s: %s', f, e)
Defensive patterns

Strategy: retry

Try / catch

from docling.service_client.exceptions import ServiceUnavailableError

for f in files:
    try:
        results.append(client.convert_file(f))
    except ServiceUnavailableError as e:
        log.error('failed %s status=%s detail=%s', f, e.status_code, e.detail)
        failed.append(f)  # retry later, don't abort the batch

Prevention

When it happens

Trigger: Service returning 5xx (e.g. 500/503) on every attempt for operations like file upload or task submission until retries run out; sustained server errors during batch processing; max_retries set low combined with a briefly failing endpoint.

Common situations: docling-serve throwing internal errors on a specific corrupt document; service under heavy load returning 503 for all requests; API rate limiting implemented as plain 503 without Retry-After.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/f3a4ae1065ffce63. Report an issue: GitHub.