AI Generated Report:
Summary
DocumentToken.get_location() in docling_core/types/doc/tokens.py enforces bbox[0] <= bbox[2] and bbox[1] <= bbox[3] via assert, but the next 4 lines of the same method clamp the values with min() / max() — so the asserts are redundant with the downstream normalization the method already performs. Near-degenerate elements (e.g. a 1-pt rule whose layout-model regression produced a slightly inverted bbox) crash export_to_doctags(add_location=True) even though the method's own output would be valid.
Repro
We hit this on a ~927-page PDF when running export_to_doctags(add_location=True) on a 153-page chunk:
File ".../docling_core/types/doc/tokens.py", line 307, in get_location
assert bbox[1] <= bbox[3], f"bbox[1]<=bbox[3] => {bbox[1]}<={bbox[3]}"
AssertionError: bbox[1]<=bbox[3] => 633.3925132751465<=625.6789665222168
The inversion is only 7.7 pt — essentially a near-zero-height element (likely a decorative rule, a tiny diacritic, or a layout-model float artifact). Probability of hitting at least one such element grows with page count, so it bites long documents in particular.
The asserts are redundant with the method's own clamp
docling-core main, docling_core/types/doc/tokens.py, the body of get_location:
assert bbox[0] <= bbox[2], f"bbox[0]<=bbox[2] => {bbox[0]}<={bbox[2]}"
assert bbox[1] <= bbox[3], f"bbox[1]<=bbox[3] => {bbox[1]}<={bbox[3]}"
x0 = bbox[0] / page_w
y0 = bbox[1] / page_h
x1 = bbox[2] / page_w
y1 = bbox[3] / page_h
x0_tok = DocumentToken.get_location_token(val=min(x0, x1), rnorm=xsize, self_closing=self_closing)
y0_tok = DocumentToken.get_location_token(val=min(y0, y1), rnorm=ysize, self_closing=self_closing)
x1_tok = DocumentToken.get_location_token(val=max(x0, x1), rnorm=xsize, self_closing=self_closing)
y1_tok = DocumentToken.get_location_token(val=max(y0, y1), rnorm=ysize, self_closing=self_closing)
The min / max calls already produce correctly-ordered location tokens regardless of input order. The asserts add no protection — they just kill export_to_doctags when the layout pipeline emits a slightly inverted box.
Suggested fix
Drop the asserts, or replace them with explicit normalization that mirrors the downstream min/max:
x0, x1 = sorted((bbox[0], bbox[2]))
y0, y1 = sorted((bbox[1], bbox[3]))
then divide by page_w / page_h and emit tokens. The same code/issue exists at docling_core/types/legacy_doc/tokens.py:177.
Environment
docling==2.93.0
docling-core==2.75.0
docling-ibm-models==3.13.2
- Python 3.12
AI Generated Report:
Summary
DocumentToken.get_location()indocling_core/types/doc/tokens.pyenforcesbbox[0] <= bbox[2]andbbox[1] <= bbox[3]viaassert, but the next 4 lines of the same method clamp the values withmin()/max()— so the asserts are redundant with the downstream normalization the method already performs. Near-degenerate elements (e.g. a 1-pt rule whose layout-model regression produced a slightly inverted bbox) crashexport_to_doctags(add_location=True)even though the method's own output would be valid.Repro
We hit this on a ~927-page PDF when running
export_to_doctags(add_location=True)on a 153-page chunk:The inversion is only 7.7 pt — essentially a near-zero-height element (likely a decorative rule, a tiny diacritic, or a layout-model float artifact). Probability of hitting at least one such element grows with page count, so it bites long documents in particular.
The asserts are redundant with the method's own clamp
docling-coremain,docling_core/types/doc/tokens.py, the body ofget_location:The
min/maxcalls already produce correctly-ordered location tokens regardless of input order. The asserts add no protection — they just killexport_to_doctagswhen the layout pipeline emits a slightly inverted box.Suggested fix
Drop the asserts, or replace them with explicit normalization that mirrors the downstream
min/max:then divide by
page_w/page_hand emit tokens. The same code/issue exists atdocling_core/types/legacy_doc/tokens.py:177.Environment
docling==2.93.0docling-core==2.75.0docling-ibm-models==3.13.2