Skip to content

BUG: task=parse rejects a 31-page A4 PDF at every zoomin, and lowering zoomin makes it worse #5307

Description

@OliverBryant

Describe the bug

task="parse" rejects a 31-page A4 PDF at every zoomin value from 1 to 6, so the document cannot be parsed at all. The error tells the caller to lower zoomin, but doing so makes the computed budget larger, not smaller.

The document is an ordinary text PDF: 31 A4 pages, 393 KB. At zoomin=3 it actually rasterizes to about 140 MP — well under the 1 GP whole-document budget. It is rejected because the budget is enforced against a worst case that overstates real usage by 10x.

To Reproduce

curl -X POST http://<host>:<port>/v1/images/ocr \
  -H "Authorization: Bearer $TOKEN" \
  -F model=DeepDoc \
  -F 'image=@thesis-31-pages.pdf;type=application/pdf' \
  -F 'kwargs={"task":"parse","zoomin":3}'
{"detail": "The uploaded PDF would rasterize to more than 1037049300 pixels in total at zoomin 3 (the parser re-renders at up to 9x when a page yields no text), exceeding the whole-document limit of 1000000000; lower `zoomin` or split the document"}

Following the advice and lowering zoomin reports a bigger number:

zoomin worst-case scale reported total rejected
3 9 1,037,049,300 yes
2 18 1,082,138,400 yes
1 9 1,037,049,300 yes

Why lowering zoomin does not help

worst_case_parse_zoom in xinference/api/pdf_ocr.py triples the scale until it reaches the limit:

def worst_case_parse_zoom(zoomin: int) -> int:
    scale = zoomin
    while scale < PDF_PARSE_RETRY_ZOOM_LIMIT:   # 9
        scale *= PDF_PARSE_RETRY_ZOOM_FACTOR    # 3
    return scale

The loop exits on scale >= 9, so it overshoots whenever zoomin is not a power-of-three divisor of 9:

zoomin escalation chain worst-case scale
1 1 → 3 → 9 9
2 2 → 6 → 18 18
3 3 → 9 9
4 4 → 12 12
5 5 → 15 15
6 6 → 18 18

So zoomin=2 is budgeted at 4x the pixels of zoomin=3, and no value in 1..6 admits a 31-page A4 document:

zoomin worst-case scale peak per A4 page 31 pages over 1 GP
1 9 45.1 MP 1.398 GP yes
2 18 180.4 MP 5.591 GP yes
3 9 45.1 MP 1.398 GP yes
4 12 80.2 MP 2.485 GP yes
5 15 125.2 MP 3.883 GP yes
6 18 180.4 MP 5.591 GP yes

There is a second, larger question behind the arithmetic. The 9x retry only fires for a page that yields no text at all, which for a text PDF essentially never happens, yet every page is budgeted as if it will. At zoomin=3 an A4 page really renders at 4.5 MP but is budgeted at 45.1 MP, so the ceiling lands at 22 A4 pages where actual usage would allow ~221:

Page size max pages at zoomin=3 (worst case) max pages by actual render
A4 22 221
A3 11 110
Letter 22 229

A 22-page cap on the default settings is restrictive for the documents this feature targets — theses, reports, papers.

Suggested fixes

Two separate things, either useful on its own:

  1. Make the advice in the error message true, or change the advice. I checked deepdoc-lib before assuming the budget was wrong here, and it is not:

    # deepdoc/parser/pdf_parser.py, __images__
    if len(self.boxes) == 0 and zoomin < 9:
        self.__images__(fnm, zoomin * 3, page_from, page_to, callback)

    The guard is on the pre-multiplication value, so a run started at 2 really does reach 18. worst_case_parse_zoom faithfully models that. The bug is therefore not the calculation but the recommendation: "lower zoomin" is not sound advice when the retry ladder is non-monotonic in zoomin.

    Either clamp upstream so the ladder never exceeds 9 (min(zoomin * 3, 9), which also caps the real allocation and would be a fix in deepdoc-lib), or keep the budget as is and stop advising a knob that can make things worse — e.g. name the largest zoomin that would fit, or just say to split the document.

  2. Don't budget every page for a retry that is conditional. Options, roughly in order of how invasive they are: validate against the requested scale and let the retry path re-validate if it triggers; keep the worst case per page (where it guards a single large MediaBox) but budget the document at the requested scale; or make the whole-document ceiling configurable so deployments with headroom can raise it.

Happy to send a PR for (1) if the clamp is the wanted direction.

Context

Found while adding remote DeepDoc parsing to xagent (xorbitsai/xagent#1161, client in xorbitsai/xagent#1271). The client behaves correctly — the 400 is treated as a remote failure and it falls back to local CPU parsing — so this is not a correctness problem downstream, but it does mean documents above ~22 A4 pages silently never get the GPU speedup they configured.

For reference, on the first 15 pages of the same document (which does pass), remote GPU parsing took 14.45s against 23.42s for local CPU, a 1.6x speedup, with full-text agreement of 99.993% between the two.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggpu

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions