Skip to content

fix(docling): drop off-by-one page-number shift in DoclingBackend - #5

Merged
bartrosa merged 1 commit into
mainfrom
cursor/critical-correctness-issues-64e3
May 23, 2026
Merged

fix(docling): drop off-by-one page-number shift in DoclingBackend#5
bartrosa merged 1 commit into
mainfrom
cursor/critical-correctness-issues-64e3

Conversation

@cursor

@cursor cursor Bot commented May 8, 2026

Copy link
Copy Markdown

Bug and impact

DoclingBackend produced wrong page numbers for every block in every parsed document. A block on page 1 reported page=2, the last page reported one past the end of the document, etc.

Downstream effects across the project's stated use cases:

  • RAG citations — every "see page N" reference is shifted by one, sending users to the wrong (or nonexistent) page.
  • bigos parse --format=json — the JSON output that ingestion pipelines persist contains incorrect page fields.
  • Search / page-anchored UIs built on Document.blocks highlight the wrong region.

This is silent data corruption: nothing crashes, no error is logged — every block just lies about its provenance.

Root cause

In src/bigos/backends/docling.py, _page_1_indexed_from_item(...) returned n + 1, on the assumption that docling's ProvenanceItem.page_no was 0-indexed.

In docling 2.92 (and the installed docling-core 2.74) prov.page_no is already 1-indexed: it is used as-is to index DoclingDocument.pages (e.g. doc.pages[prov.page_no]), and a single-page document's pages dict is keyed {1: ...}. Adding +1 on top therefore shifts every block.

Reproducer (single-page PDF fixture in tests/fixtures/simple_text.pdf):

src = Source(uri=pdf.as_uri(), mime_type="application/pdf", sha256=sha256_file(pdf))
doc = await DoclingBackend().run(src)
print({b.page for b in doc.blocks if b.page is not None})
# before fix: {2}
# after fix:  {1}

The existing tests only asserted block-kind counts, not page numbers, so the bug slipped through the initial docling integration review.

Fix and validation

  • Pass the docling page number through unchanged after int(...) coercion. Treat < 1 (and missing/bad values) as unknown.
  • Document the 1-indexed convention in the helper's docstring so future edits do not re-introduce the shift.

Validation:

  • New focused unit test test_page_helper_passes_through_1_indexed covers the in-range, missing-prov, and bad-value branches without requiring docling at runtime.
  • New slow regression test_parse_simple_text_page_number_is_one runs the docling backend on the existing single-page fixture and asserts every block reports page == 1.
  • Full test suite (uv run pytest) — 67 passed, no regressions.

The fix is minimal (1 file, ~10 lines) and does not touch any other behavior.

Open in Web View Automation 

…dexed

DoclingBackend.`_page_1_indexed_from_item` was treating
`ProvenanceItem.page_no` as 0-indexed and adding +1 on top. In docling
2.92 the field is already 1-indexed (it is used as-is to index
`DoclingDocument.pages`, e.g. `doc.pages[prov.page_no]` and
`doc.pages[1]` for a single-page document).

Effect of the bug: every `Block.page` value emitted by the docling
backend was off by one. A block on the first page reported `page=2`,
the last page reported one past the end, etc. Downstream consumers
(RAG citations, page-anchored UIs, search snippets, the `bigos parse`
JSON output) were therefore pointing users to the wrong page. The
existing per-block tests only asserted block-kind counts, not page
numbers, so the regression slipped through review with the initial
docling integration.

Reproducer (1-page PDF):

    doc = await DoclingBackend().run(src)
    {b.page for b in doc.blocks if b.page is not None}  # was {2}, now {1}

Fix: pass the docling page number through unchanged after coercion,
treat `< 1` as unknown, and document the convention so future edits
do not re-introduce the shift.

Tests: a focused unit test covers the helper for the in-range,
out-of-range, missing-prov and bad-value paths; a slow end-to-end test
runs the docling backend against the existing single-page fixture and
asserts every block reports `page == 1`.

Co-authored-by: Bartłomiej Rosa <bartrosa@users.noreply.github.com>
@bartrosa
bartrosa marked this pull request as ready for review May 23, 2026 12:45
@bartrosa
bartrosa merged commit 39fee37 into main May 23, 2026
2 checks passed
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.

2 participants