{"record":{"id":"90a0f1e7484773b8","repo":"BerriAI/litellm","slug":"azure-document-intelligence-returned-202-but-no-op","errorCode":null,"errorMessage":"Azure Document Intelligence returned 202 but no Operation-Location header found","messagePattern":"Azure Document Intelligence returned 202 but no Operation-Location header found","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/azure_ai/ocr/document_intelligence/transformation.py","lineNumber":584,"sourceCode":"            self._check_timeout(start_time=start_time, timeout_secs=timeout_secs)\n\n            # Poll the operation status\n            response = await client.get(url=operation_url, headers=headers)\n\n            # Check operation status\n            status = self._check_operation_status(response=response)\n\n            if status == \"succeeded\":\n                return response\n            elif status == \"running\":\n                # Wait before polling again\n                retry_after = self._get_retry_after(response=response)\n                await asyncio.sleep(retry_after)\n\n    def _get_polling_target(self, raw_response: httpx.Response) -> tuple[str, dict[str, str]]:\n        operation_url: Final = raw_response.headers.get(\"Operation-Location\")\n        if not operation_url:\n            raise ValueError(\"Azure Document Intelligence returned 202 but no Operation-Location header found\")\n\n        # Reject cross-origin polling URLs — the auth headers\n        # below would otherwise leak to whatever URL the upstream\n        # (or an attacker-controlled upstream) returns. VERIA-51.\n        try:\n            assert_same_origin(operation_url, str(raw_response.request.url))\n        except SSRFError as ssrf_err:\n            raise ValueError(f\"Azure Document Intelligence: rejected polling URL ({ssrf_err})\")\n\n        poll_headers = {\"Ocp-Apim-Subscription-Key\": raw_response.request.headers.get(\"Ocp-Apim-Subscription-Key\", \"\")}\n        return operation_url, poll_headers\n\n    def _transform_completed_response(self, model: str, raw_response: httpx.Response) -> OCRResponse:\n        \"\"\"\n        Transform a completed Azure Document Intelligence analyze operation\n        into the Mistral OCR response shape, preserving Azure-native\n        `analyzeResult` fields (`content`, `tables`, `keyValuePairs`) as\n        top-level response fields.","sourceCodeStart":566,"sourceCodeEnd":602,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/azure_ai/ocr/document_intelligence/transformation.py#L566-L602","documentation":"Raised when the initial Azure DI submit returns HTTP 202 but the Operation-Location response header is absent, leaving LiteLLM no URL to poll for the async analysis result. Azure DI always includes this header on an accepted analyze request, so its absence indicates a protocol break — a proxy stripping headers, a wrong endpoint that returns 202 from something else, or an API-version mismatch.","triggerScenarios":"An intermediary (corporate proxy, API gateway, custom base URL) returning its own 202 without forwarding Azure's Operation-Location; api_base pointing at a non-DI endpoint that happens to return 202; Azure API version changes altering response headers.","commonSituations":"Self-hosted gateways or mTLS terminators dropping unknown headers; misconfigured api_base; testing with mocks that don't emulate the header; rare Azure-side incidents.","solutions":["Ensure api_base/AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT points directly at your Document Intelligence resource and the model is a valid prebuilt/custom model ID.","Check intermediaries (proxy/gateway) for header stripping and whitelist Operation-Location.","Retry once — transient Azure anomalies do occur; if persistent, capture headers with curl to confirm what's returned."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    resp = litellm.aocr_document(model=m, document=doc)\nexcept ValueError as e:\n    if \"no Operation-Location header\" in str(e):\n        raise InfrastructureError(\"DI endpoint/proxy dropped Operation-Location; check api_base and gateways\") from e\n    raise","preventionTips":["Point api_base directly at the cognitive services resource.","Ensure proxies/gateways forward the Operation-Location header.","Mock servers must emit the header to be usable in tests."],"tags":["azure","document-intelligence","ocr","headers","proxy","polling"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}