docling-project / docling-project/docling-core
`HierarchicalChunker` records `''` in `meta.headings` for a heading whose text is in an `InlineGroup`, and emits that heading's text as a body chunk
- Dominant language
- HTML
- Stars
- 282
- Forks
- 214
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 21
Description
The Markdown backend represents a heading of any level with more than one inline run as a `SectionHeaderItem` with `text=""` and one `InlineGroup` child holding the runs. A `#` heading gives a `TitleItem` of the same shape. `## [0.68.0] - 2026-07-24` is one such heading. A heading that is a single link or a single emphasis span keeps its text on the item. Measured on docling 2.124.0.
`MarkdownDocSerializer` handles the shape. `export_to_markdown()` renders `## [Release](https://example.com/releases) notes`. `HierarchicalChunker` does not:
- It stores the heading item in `heading_by_level` and builds `meta.headings` from `item.text`. The heading contributes `''`. A `TitleItem` of this shape gives `['']`.
- The loop `continue`s on a heading without marking its children visited. The `InlineGroup` then arrives as an item of its own and is serialized as content. The result is a chunk whose text is the heading.
`HybridChunker` starts from these chunks and inherits both, and adds a re-serialization defect of its own, #770. Every chunk under such a heading carries an empty string where its heading should be, and the heading text lands in the body of the first chunk. The same document shape appears in #740 for the LaTeX serializer, fixed by #743 in 2.95.0, and in #750 for the DocLang serializer.
Reproduced on docling-core 2.96.0. The loop is unchanged on `main`, in `hierarchical_chunker.py`, `HierarchicalChunker.chunk`.
## Reproduction
```python
from docling_core.types.doc.document import DoclingDocument
from docling_core.types.doc.labels import DocItemLabel
from docling_core.transforms.chunker.hierarchical_chunker import HierarchicalChunker
doc = DoclingDocument(name="t")
doc.add_title(text="Sample")
heading = doc.add_heading(text="", level=1)
group = doc.add_inline_group(parent=heading)
doc.add_text(label=DocItemLabel.TEXT, text="Release", parent=group, hyperlink="https://example.com/releases")
doc.add_text(label=DocItemLabel.TEXT, text="notes", parent=group)
para = doc.add_inline_group()
doc.add_text(label=DocItemLabel.TEXT, text="Install with", parent=para)
doc.add_code(text="pip install x", parent=para)
doc.add_text(label=DocItemLabel.TEXT, text="first.", parent=para)
print(doc.export_to_markdown())
for c in HierarchicalChunker().chunk(doc):
print(c.meta.headings, repr(c.text))
```
Output on 2.96.0:
```
# Sample
## [Release](https://example.com/releases) notes
Install with `pip install x` first.
['Sample', ''] '[Release](https://example.com/releases) notes'
['Sample', ''] 'Install with `pip install x` first.'
```
A real changelog converted with docling 2.124.0 and chunked gives `headings=['Changelog', '', 'Added']` on every chunk, plus one extra chunk per release heading whose text is the heading itself.
## Expected
```
['Sample', 'Release notes'] 'Install with `pip install x` first.'
```
`meta.headings` should carry the heading's plain text, as it does for a heading whose text sits on the item. How formatting and hyperlinks inside a heading render is the serializer's concern and does not belong in the metadata. No chunk should have the heading's runs as its content.
Contributor guide
Research direction
Start with hierarchical_chunker.py and the HierarchicalChunker.chunk method, then run the reproduction from the issue against the current implementation. Check how heading_by_level, item.text, and InlineGroup traversal affect meta.headings and chunk content; done means formatted heading runs are absent from body chunks and metadata contains their plain text, matching the expected output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100