Skip to content

fix(cloud): migrate off deprecated /extract endpoint and stop misreading deprecation 429 as a quota error - #57

Closed
gbharg wants to merge 1 commit into
NanoNets:mainfrom
gbharg:fix/deprecated-extract-endpoint
Closed

fix(cloud): migrate off deprecated /extract endpoint and stop misreading deprecation 429 as a quota error#57
gbharg wants to merge 1 commit into
NanoNets:mainfrom
gbharg:fix/deprecated-extract-endpoint

Conversation

@gbharg

@gbharg gbharg commented Jul 2, 2026

Copy link
Copy Markdown

Summary

Cloud mode currently fails for users with a valid API key and unused quota, reporting a misleading Rate limit exceeded (10k/month) error. The root cause is a deprecated endpoint whose deprecation response is misread as a quota error.

Symptom

With a valid Nanonets key configured, any cloud extraction (e.g. extract_markdown(), parse_pdf) raises:

ConversionError: Rate limit exceeded (10k/month). Please try again later.

…even on a brand-new key that has never been used. OCR then silently fails.

Root cause

docstrange/processors/cloud_processor.py POSTs to nanonets' deprecated /extract endpoint:

self.api_url = "https://extraction-api.nanonets.com/extract"

Nanonets now returns HTTP 429 for that endpoint, but with a deprecation body — not a quota body:

{"detail": "The /extract endpoint is deprecated. Please migrate to /api/v1/extract."}

The 429 handler inspects only the status code and never reads the body, so whenever an API key is present it unconditionally raises Rate limit exceeded (10k/month). A deprecation notice is thus reported to the user as an exhausted quota.

Fix

  1. Migrate to the current sync endpoint https://extraction-api.nanonets.com/api/v1/extract/sync.
  2. Send output_format (required by the new endpoint), mapped from the legacy output_type vocabulary (markdown|html|csv pass through; flat-json and the specified-* variants map to json). output_type is still sent for backward compatibility.
  3. Body-aware 429 handling — inspect the response body before assuming a quota problem:
    • a deprecation notice surfaces the real message and guidance to upgrade, instead of a fabricated quota error;
    • a genuine rate-limit body is still reported as a rate-limit error, and now includes the server's own detail.
  4. Parse the new nested response shape result.<format>.content, while keeping backward compatibility with the legacy top-level content field.
  5. Tests — added tests/test_cloud_deprecation.py, fully offline (HTTP + file I/O mocked; no API key or network needed), covering the endpoint, request params, deprecation-vs-quota 429 handling, and both response shapes.

Verification

Confirmed against the live API (key redacted):

  • POST /extract (old) → HTTP 429, body {"detail": "The /extract endpoint is deprecated. Please migrate to /api/v1/extract."}.
  • POST /api/v1/extract/sync without output_format → HTTP 422 (missing required field), key accepted (no 401/403).
  • POST /api/v1/extract/sync with output_format=markdown + Bearer key → HTTP 200, "success": true, correct OCR of a scanned document.

After applying this change, cloud extraction returns real OCR content on a valid key, and a deprecation 429 (if it ever recurs) is no longer misreported as a quota error.

Backward compatibility

  • The legacy top-level content response field is still handled.
  • output_type is still sent alongside the new output_format.
  • No public API or signature changes.

🤖 Generated with Claude Code

…ing deprecation 429 as a quota error

Cloud mode POSTed to nanonets' deprecated `/extract` endpoint, which now
responds with HTTP 429 and a body of
`{"detail": "The /extract endpoint is deprecated. Please migrate to
/api/v1/extract."}`. The 429 handler only inspected the status code, so
whenever an API key was present it unconditionally raised
"Rate limit exceeded (10k/month)". Users with a valid key and unused quota
therefore saw a false "quota exceeded" error and OCR silently failed.

Changes:
- Point `api_url` at the current sync endpoint
  `https://extraction-api.nanonets.com/api/v1/extract/sync`.
- Send `output_format` (required by the new endpoint), mapped from the legacy
  `output_type` vocabulary; `output_type` is still sent for backward compat.
- Make the 429 handler body-aware: a deprecation notice now surfaces the real
  message instead of a fabricated quota error; genuine rate-limit bodies are
  still reported as such (and now include the server's detail).
- Parse the new nested response shape `result.<format>.content` while keeping
  backward compatibility with the legacy top-level `content` field.
- Add offline (mocked) unit tests covering the endpoint, request params,
  deprecation-vs-quota 429 handling, and both response shapes.

Verified: raw `POST /api/v1/extract/sync` with `output_format` and a valid
Bearer key returns HTTP 200 with correct OCR; the previous `/extract` call
returned the deprecation 429 described above.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gbharg

gbharg commented Jul 2, 2026

Copy link
Copy Markdown
Author

Closing this one -- we are handling the change downstream for now. Thanks!

@gbharg gbharg closed this Jul 2, 2026
@gbharg
gbharg deleted the fix/deprecated-extract-endpoint branch July 2, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant