{"record":{"id":"d3537274dba2f5b7","repo":"docling-project/docling","slug":"service-returned-http-response-status-code-after","errorCode":null,"errorMessage":"Service returned HTTP {response.status_code} after retries.","messagePattern":"Service returned HTTP (.+?) after retries\\.","errorType":"exception","errorClass":"ServiceUnavailableError","httpStatus":null,"severity":"error","filePath":"docling/service_client/client.py","lineNumber":611,"sourceCode":"            return None, self._exponential_backoff_delay(attempt)\n        raise ServiceUnavailableError(\n            error_message,\n            status_code=response.status_code,\n            detail=self._http_error_detail(response),\n        )\n\n    def _retry_with_retry_after_header(\n        self,\n        response: httpx.Response,\n        attempt: int,\n        max_retries: int,\n    ) -> tuple[httpx.Response | None, float]:\n        retry_after_delay = self._retry_after_delay_seconds(response)\n        if retry_after_delay is None:\n            return response, 0.0\n        if attempt < max_retries:\n            return None, retry_after_delay\n        raise ServiceUnavailableError(\n            f\"Service returned HTTP {response.status_code} after retries.\",\n            status_code=response.status_code,\n            detail=self._http_error_detail(response),\n        )\n\n    def _exponential_backoff_delay(self, attempt: int) -> float:\n        return HTTP_RETRY_BACKOFF_BASE_SECONDS * (2**attempt)\n\n    def _transport_retry_delay(\n        self,\n        *,\n        method: str,\n        exc: httpx.HTTPError,\n        attempt: int,\n        max_retries: int,\n    ) -> float | None:\n        method_name = method.upper()\n        if (","sourceCodeStart":593,"sourceCodeEnd":629,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/service_client/client.py#L593-L629","documentation":"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.","triggerScenarios":"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.","commonSituations":"Batch conversion tripping rate limits; shared service instances throttling per-client; retry budget (default few attempts) shorter than the throttle window.","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."],"exampleFix":"# before\nclient = DocumentConverterClient(url, max_concurrency=64)\nresults = [client.convert_file(f) for f in many_files]  # 429s exhaust retries\n\n# after\nclient = DocumentConverterClient(url, max_concurrency=4, http_retries=8)\nfrom docling.service_client.exceptions import ServiceUnavailableError\nimport time\nfor f in many_files:\n    for attempt in range(3):\n        try:\n            results.append(client.convert_file(f)); break\n        except ServiceUnavailableError:\n            time.sleep(30)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from docling.service_client.exceptions import ServiceUnavailableError\nimport time\n\nfor attempt in range(5):\n    try:\n        result = client.convert_file(f)\n        break\n    except ServiceUnavailableError as e:\n        if e.status_code not in (429, 503):\n            raise\n        time.sleep(min(60, 5 * 2 ** attempt))","preventionTips":["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."],"tags":["service-client","retry","rate-limit","retry-after","unavailable"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}