docling-project/docling · error · ServiceUnavailableError

Service request failed after retry loop.

Error message

Service request failed after retry loop.

What it means

This is the terminal fallback of the async client's retry loop: the request was attempted max_retries+1 times, every attempt either failed transport-level with delays exhausted or returned a retryable HTTP status, and the loop exited without a usable response. ServiceUnavailableError is raised to signal the service did not yield a successful response within the retry budget. Unlike error 350, the last attempt may have been an HTTP-level retry (429/5xx) rather than a transport exception.

Source

Thrown at docling/service_client/_async_client.py:709

                    method=method_name,
                    exc=exc,
                    attempt=attempt,
                    max_retries=max_retries,
                )
                if delay is not None:
                    await asyncio.sleep(delay)
                    continue
                raise ServiceUnavailableError(
                    "Service transport request failed.",
                    detail=str(exc),
                ) from exc
            result, delay = self._check_retry(response, attempt, max_retries)
            if result is not None:
                return result
            if delay > 0:
                await asyncio.sleep(delay)

        raise ServiceUnavailableError("Service request failed after retry loop.")

    async def _submit_convert_task(
        self,
        source: SourceType,
        options: ConvertDocumentsRequestOptions,
        target: SubmitTarget,
        async_client: httpx.AsyncClient,
        request_headers: dict[str, str] | None = None,
    ) -> TaskStatusResponse:
        source = self._normalize_source(source)
        source_name = self._source_name(source)
        logger.info("Submitting convert task for source=%s", source_name)
        if isinstance(source, HttpSourceRequest):
            request = ConvertDocumentsRequest(
                options=options,
                sources=[source],
                target=target,
            )

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Increase http_retries and/or connect/read timeouts on the client so the retry window covers transient outages.
  2. Reduce request concurrency to lower pressure on the service.
  3. Check service health/logs and wait for it to recover before resubmitting.
  4. Implement application-level backoff and resubmit the failed request later.

Example fix

# before
client = DocumentConverterClient(base_url=url)  # default retries
result = await client.convert_file(f)  # ServiceUnavailableError after retry loop

# after
client = DocumentConverterClient(base_url=url, http_retries=8, http_read_timeout=120.0)
async with client:
    try:
        result = await client.convert_file(f)
    except ServiceUnavailableError:
        await asyncio.sleep(60)
        result = await client.convert_file(f)
Defensive patterns

Strategy: retry

Try / catch

from docling.service_client.exceptions import ServiceUnavailableError

try:
    result = await client.convert_file(f)
except ServiceUnavailableError:
    await asyncio.sleep(backoff)
    result = await client.convert_file(f)  # resubmit after service recovers

Prevention

When it happens

Trigger: Service persistently returning 503/429/502 across all attempts with Retry-After or backoff delays; sustained overload or the service being down for maintenance; retry budget (http_retries) too small for the outage duration.

Common situations: Hammering a small docling-serve instance with a large batch until it sheds load; service restarting/deploying mid-job; autoscaling cold start taking longer than the client retry window.

Related errors


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