Azure / Azure/azure-sdk-for-python
[Document Intelligence] queryFields against on-prem Layout container returns 202 then pins the operation at status=running forever (no terminal error)
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 3.4k
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 193
Description
- **Package Name**: azure-ai-documentintelligence
- **Package Version**: 1.0.2 (azure-core 1.41.0)
- **Operating System**: macOS (arm64); container image `linux/amd64` (`layout-4.0`)
- **Python Version**: 3.14.6
**Describe the bug**
Sending an analyze request with the `queryFields` add-on to an on-premises (connected)
Document Intelligence **Layout container** never completes. The initial `POST …:analyze`
returns `202 Accepted`, but the operation then stays at `"status": "running"` **indefinitely**
and never transitions to `succeeded` or `failed`. Because `poller.result()` has no overall
deadline, the client hangs forever with **no exception raised**.
Two controls prove the request itself is valid:
- The same request **without** `queryFields` succeeds against the same container in seconds.
- The same request **with** `queryFields` succeeds against the **cloud** endpoint in seconds.
This implies the query-fields add-on isn't implemented in the container image — but instead of
failing the operation with a terminal error, the container leaves it pinned at `running`. The
container is idle (~2% CPU) throughout, so this is not a latency/throughput issue.
**To Reproduce**
Steps to reproduce the behavior:
1. Run the connected Layout container:
`mcr.microsoft.com/azure-cognitive-services/form-recognizer/layout-4.0` (API `2024-11-30`),
with valid `Eula`/`billing`/`apiKey` (`GET /status` returns 200).
2. Call `begin_analyze_document` with the query-fields add-on:
```python
import asyncio, io
from azure.ai.documentintelligence.aio import DocumentIntelligenceClient
from azure.ai.documentintelligence.models import DocumentAnalysisFeature
from azure.core.credentials import AzureKeyCredential
ENDPOINT = "http://localhost:5000" # container does not validate the key
async def main():
async with DocumentIntelligenceClient(ENDPOINT, AzureKeyCredential("placeholder")) as client:
with open("sample.pdf", "rb") as f:
body = f.read()
poller = await client.begin_analyze_document(
"prebuilt-layout",
body=io.BytesIO(body),
features=[DocumentAnalysisFeature.QUERY_FIELDS],
query_fields=["VendorName", "InvoiceTotal"],
)
result = await poller.result() # never returns; no exception
print(result)
asyncio.run(main())
```
3. Observe that the call never returns and never raises.
The same behavior at the HTTP level (isolates the SDK):
```console
$ curl -s -D - -o /dev/null -X POST \
"http://localhost:5000/documentintelligence/documentModels/prebuilt-layout:analyze?api-version=2024-11-30&features=queryFields&queryFields=VendorName,InvoiceTotal" \
-H "Content-Type: application/octet-stream" --data-binary @sample.pdf
HTTP/1.1 202 Accepted
Operation-Location: http://localhost:5000/documentintelligence/documentModels/prebuilt-layout/analyzeResults/?api-version=2024-11-30
$ curl -s "http://localhost:5000/documentintelligence/documentModels/prebuilt-layout/analyzeResults/?api-version=2024-11-30"
{"status":"running", ...}
# polled repeatedly over minutes -> always "running", never "succeeded"/"failed"
```
**Expected behavior**
The operation transitions to `"status": "failed"` with a terminal error (e.g. `InvalidArgument`
or a "feature not supported by this container" message), so `poller.result()` raises
`HttpResponseError` promptly instead of hanging.
**Screenshots**
N/A — text output shown above (`202 Accepted` followed by an indefinite `"status": "running"`).
**Additional context**
A/B/C evidence:
| Request | Backend | Result |
| --- | --- | --- |
| `prebuilt-layout`, no add-on | on-prem container | ✅ succeeds in seconds |
| `prebuilt-layout` + `queryFields` | on-prem container | ⌛ `status=running` forever, no error |
| `prebuilt-layout` + `queryFields` | cloud (Azure) | ✅ succeeds in seconds, returns fields |
Root cause appears to be the async LRO contract: the `POST` validates only the request envelope
(`queryFields` is a valid parameter in the `2024-11-30` contract the container shares with cloud),
so it returns `202` and queues an operation; the container then reaches the query-fields stage,
which isn't shipped in the image, and leaves the operation at `running` rather than transitioning
it to `failed`. Each poll is itself a valid `200 {"status":"running"}`, so nothing raises.
Requests:
1. **Service/container:** fail the operation with a terminal error when an unsupported add-on is
requested, instead of leaving it at `running`.
2. **Docs:** explicitly document which add-on capabilities (`queryFields`, `keyValuePairs`, …)
are supported in the containers vs. cloud — this is currently undocumented.
3. **SDK (optional):** consider a documented default overall deadline for the analyze poller, or
clearer guidance, so a service-side operation stuck at `running` doesn't manifest as a silent,
unbounded client hang.
Possibly related (not duplicates): #43085 (error handling), #42520 (LRO examples/timeouts),
#42152 (poller blocks loop), #43114 (`polling_interval` not respected), #36841 (error messaging
for unsupported inputs), #44449 (container + analyze, but 100% CPU — opposite symptom).
Contributor guide
Assessment
This issue has not been assessed yet.