Summary
Hybrid mode (docling-fast backend) corrupts table structure on dense,
multi-column engineering datasheets: logical rows are collapsed, cells are
misaligned, and one table's dimensions changed from 1x4 (local) to 10x4
(hybrid). The server log shows the direct mechanism — dozens of
Orphan pdf_cell ... recovered to row=N by nearest-row fallback warnings
from docling_ibm_models/tableformer/.../matching_post_processor.py, i.e.
cells that matched neither a predicted row band nor column band being
force-snapped to the nearest one.
This is the same class of bug as #627 (which reports full mode on a
financial PDF), but two new data points:
- It also happens in auto mode (the default triage path), not only full.
- Switching TableFormer to FAST mode does NOT help — the corruption is
identical, so it is not a mode-selection issue; the predicted grid itself
misses the real cells on this document class.
Environment
- opendataloader-pdf: 2.5.7 (pip,
opendataloader-pdf[hybrid])
- docling: 2.126.0, docling-core as shipped with it
- Python 3.12, Java OpenJDK 11.0.32
- Backend:
opendataloader-pdf-hybrid --port 5002 --device cpu (CPU-only)
- Client: default triage (
--hybrid docling-fast, hybrid_mode=auto)
- OS: Ubuntu 24.04, 22 cores / 44 threads
Reproduction
pip install "opendataloader-pdf[hybrid]"
- Start backend:
opendataloader-pdf-hybrid --port 5002 --device cpu
- Parse a dense multi-column datasheet (attached: Xphor 16x200GFC PIC
datasheet, 11 pages, 10 tables, 2-column layout with many small spec
tables):
import opendataloader_pdf
opendataloader_pdf.convert(
input_path=["Xphor_16x200GFC_datasheet_rev0p2.pdf"],
output_dir="out_hybrid",
format="markdown,json",
hybrid="docling-fast",
)
- Repeat with
--hybrid off (pure local Java mode) into out_local and
compare table dimensions per page.
Observed behavior — table dimensions, same document
| # |
page |
local-only |
hybrid (ACCURATE) |
hybrid (FAST, patched) |
| 1 |
1 |
17x5 |
17x5 |
17x5 |
| 2 |
5 |
10x6 |
9x6 |
9x6 |
| 3 |
5 |
17x6 |
16x5 |
16x5 |
| 4 |
5 |
4x5 |
3x4 |
3x4 |
| 5 |
6 |
6x5 |
6x5 |
6x5 |
| 6 |
7 |
7x5 |
6x4 |
8x4 |
| 7 |
7 |
13x4 |
12x4 |
12x4 |
| 8 |
8 |
1x4 |
10x4 |
10x4 |
| 9 |
8 |
11x4 |
3x5 |
3x5 |
| 10 |
11 |
3x5 |
— (missing) |
— (missing) |
Server log evidence (ACCURATE run)
WARNING: Orphan pdf_cell 51 recovered to row=2 by nearest-row fallback (col=1, y=553.5, dist=62.4)
WARNING: Orphan pdf_cell 52 recovered to row=2 by nearest-row fallback (col=1, y=553.5, dist=62.4)
...
WARNING: Orphan pdf_cell 158 recovered to row=9 by nearest-row fallback (col=1, y=1146.3, dist=46.8)
22 such warnings in the ACCURATE run, 18 in the FAST run. The recovery path
in matching_post_processor.py exists so text is not silently dropped, but
snapping cells to the wrong row/column is exactly what produces the
collapsed/misaligned tables above — content survives, structure does not.
Root-cause observation
opendataloader_pdf/hybrid_server.py hardcodes:
"table_structure_options": TableStructureOptions(mode=TableFormerMode.ACCURATE),
with no CLI flag or environment variable to override it. On documents whose
real table grid differs from the model's predicted bands (dense spec tables,
merged cells, small fonts), every unmatched cell takes the nearest-row/col
fallback and the table is corrupted in a way that is hard to detect without
cross-checking against the rendered page.
Suggestion
- Expose the TableFormer mode (and ideally
do_table_structure) as a
backend/client option so users can fall back per document class.
- Consider triaging tables with strong border/ruling structure to a
deterministic path instead of the neural grid, or at least emit a
machine-readable warning when orphan-fallback recovery touches more than
N cells in one table, so RAG pipelines can flag low-confidence tables.
Attachments
- Xphor_16x200GFC_datasheet_rev0p2.pdf (reproducer)
- out_local / out_hybrid JSON + Markdown outputs
- hybrid-server.log (ACCURATE and FAST runs)
Summary
Hybrid mode (
docling-fastbackend) corrupts table structure on dense,multi-column engineering datasheets: logical rows are collapsed, cells are
misaligned, and one table's dimensions changed from 1x4 (local) to 10x4
(hybrid). The server log shows the direct mechanism — dozens of
Orphan pdf_cell ... recovered to row=N by nearest-row fallbackwarningsfrom
docling_ibm_models/tableformer/.../matching_post_processor.py, i.e.cells that matched neither a predicted row band nor column band being
force-snapped to the nearest one.
This is the same class of bug as #627 (which reports
fullmode on afinancial PDF), but two new data points:
identical, so it is not a mode-selection issue; the predicted grid itself
misses the real cells on this document class.
Environment
opendataloader-pdf[hybrid])opendataloader-pdf-hybrid --port 5002 --device cpu(CPU-only)--hybrid docling-fast, hybrid_mode=auto)Reproduction
pip install "opendataloader-pdf[hybrid]"opendataloader-pdf-hybrid --port 5002 --device cpudatasheet, 11 pages, 10 tables, 2-column layout with many small spec
tables):
--hybrid off(pure local Java mode) intoout_localandcompare table dimensions per page.
Observed behavior — table dimensions, same document
note-row to a 10x4 block (rows pulled in from elsewhere), table [AI-Safety] Hidden Off-page AI Injection Prompts in Documents #9 lost
8 of 11 rows.
hybrid_server.pyline ~494 fromTableFormerMode.ACCURATEtoTableFormerMode.FAST): 9 tables, 82 rows,393 cells — same corruption pattern.
Server log evidence (ACCURATE run)
22 such warnings in the ACCURATE run, 18 in the FAST run. The recovery path
in
matching_post_processor.pyexists so text is not silently dropped, butsnapping cells to the wrong row/column is exactly what produces the
collapsed/misaligned tables above — content survives, structure does not.
Root-cause observation
opendataloader_pdf/hybrid_server.pyhardcodes:with no CLI flag or environment variable to override it. On documents whose
real table grid differs from the model's predicted bands (dense spec tables,
merged cells, small fonts), every unmatched cell takes the nearest-row/col
fallback and the table is corrupted in a way that is hard to detect without
cross-checking against the rendered page.
Suggestion
do_table_structure) as abackend/client option so users can fall back per document class.
deterministic path instead of the neural grid, or at least emit a
machine-readable warning when orphan-fallback recovery touches more than
N cells in one table, so RAG pipelines can flag low-confidence tables.
Attachments