docling-project / docling-project/docling
pdfium outline is silently truncated at 15 levels
- Dominant language
- Python
- Stars
- 66.4k
- Forks
- 4.8k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 84
Description
### Bug
`extract_outline_from_pdfium()` calls `pdoc.get_toc()` without arguments. pypdfium2
walks the outline recursively and defaults to `max_depth=15`, dropping every entry
below that level with only a log line:
```
Maximum recursion depth 15 reached (subtree skipped).
```
The other extractor in the same module, `extract_outline_from_docling_parse()`, walks
iteratively and is unbounded — `test_outline_deep_chain_does_not_raise_recursion_error`
asserts it handles 5000 levels. So the two extractors silently disagree on any document
whose table of contents is deeper than 15, and `PyPdfiumDocumentBackend` loses those
entries.
### Steps to reproduce
Build a one-page PDF whose outline is a chain 20 levels deep, then:
```python
import pypdfium2 as pdfium
from docling.utils.pdf_outline import extract_outline_from_pdfium
doc = pdfium.PdfDocument("deep_outline.pdf")
print(len(list(doc.get_toc()))) # 15 <- default bound
print(len(list(doc.get_toc(max_depth=128)))) # 20
print(len(extract_outline_from_pdfium(doc))) # 15 <- entries 16..20 are gone
```
Observed on both pypdfium2 4.30.0 and 5.13.0; the signature `get_toc(max_depth=15, ...)`
is the same in each.
### Docling version
2.124.0
### Python version
3.13.15
Contributor guide
Research direction
Start in docling/utils/pdf_outline.py with extract_outline_from_pdfium() and compare its pypdfium2 get_toc() call with extract_outline_from_docling_parse(). Run test_outline_deep_chain_does_not_raise_recursion_error and reproduce the 20-level outline case; done means the pdfium extractor retains entries beyond level 15 and the regression is covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 86/100