GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||
GeezerVison is showing github.com — fix: don't retry an API error that declares itself non-retryable by CyMule · Pull Request #358 · Unstructured-IO/unstructured-python-client Conversation
|
| Error body | Before | After |
|---|---|---|
{"detail": …, "retryable": false, …} |
retried | returned at once |
{"detail": …, "retryable": true, …} |
retried | retried |
{"detail": "Internal server error"} (no verdict) |
retried | retried |
non-JSON, "retryable": "false" (string), unparsable |
retried | retried |
The same check covers the split-PDF path. A chunk that gets a declared non-retryable 5xx is sent once instead of using up its own per-chunk retry budget.
The Unstructured API publishes its own verdict next to detail on errors it raises deliberately: error_type, audience, retryable and error_reason. An OCR (Tesseract) timeout, for example, answers 503 with retryable: false. The same image re-sent to the same time budget times out again. The retry loop matches on status before any caller can read the body, so no caller can act on that verdict. In production, one Transform record received 12 HTTP 500s across two dispatches over 670s. Attempt-6 retry markers are 98.6% as common as attempt-1 markers, so these failures do not recover on retry.
The retry loop is the one place that both whole-document requests and split-PDF chunk requests pass through. A caller-side hook can't reach the split-PDF chunks, because the split hook sends them through its own HTTP client. The check only ever stops a retry. A declared retryable: true never makes a status retryable that wasn't already.
retries.py already carries hand edits (#342). gen.yaml has persistentEdits enabled.
"retryable": false changes behaviour. An unread streamed response is never consumed; it keeps status-based retries.make lint is clean (pylint 10/10, mypy).partition / partition_async through a mocked transport.RecursionError on a deeply nested body) is fixed.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 5 files
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/unstructured_client/utils/retries.py">
<violation number="1" location="src/unstructured_client/utils/retries.py:94">
P3: This exception list misses `httpx.StreamConsumed` and `httpx.StreamClosed`, so a matching streamed response that was consumed or closed before inspection becomes a permanent error and skips the existing status retry. Treat these unavailable-body exceptions like `ResponseNotRead` and return `False`.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
View guided diff | Re-trigger cubic
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.