Bug Description
_extract_headers in merge_table.py crashes with ValueError: max() iterable argument is empty when a table segment contains only separator rows (or rows where row['tr'] is a string rather than a dict).
Root Cause
In merge_table.py line 25-28:
max_cols = max(
len(row['tr']) for row in segment
if _is_table_row(row) and isinstance(row['tr'], dict)
)
The generator filters for rows where row['tr'] is a dict, but when all rows in a segment have row['tr'] as a string (e.g. 'table_separator'), the generator yields nothing and max() raises ValueError.
Minimal Reproducible Example
from markdown_to_data import Markdown
# A lone separator line gets classified as a table row but has no dict data
md = Markdown("---|---")
print(md.md_dict) # ValueError: max() iterable argument is empty
All of these crash:
Markdown("---|---")
Markdown("|---|---|")
Markdown("text\n---|---\nmore text")
Markdown("# Heading\n\n---|---\n\nParagraph")
In real-world documents this commonly happens with content like horizontal rules written as ---|---, or technical text near pipe characters that creates isolated separator-only segments.
Full Traceback
Traceback (most recent call last):
File "<string>", line 3, in <module>
File "markdown_to_data/markdown_to_data.py", line 107, in md_dict
self._md_dict = hierarchy_with_merged_markdown_lines(self.md_list)
File "markdown_to_data/markdown_to_data.py", line 101, in md_list
self._md_list = merge_classified_markdown_lines(classified_list=self.classified_lines)
File "markdown_to_data/to_python/to_python_objects.py", line 55, in merge_classified_markdown_lines
merged_elements = merge_tables(classified_md=merged_elements)
File "markdown_to_data/to_python/merging_multiline_objects/merge_table.py", line 112, in merge_tables
result.append(_process_table_segment(current_segment))
File "markdown_to_data/to_python/merging_multiline_objects/merge_table.py", line 79, in _process_table_segment
headers = _extract_headers(segment)
File "markdown_to_data/to_python/merging_multiline_objects/merge_table.py", line 25, in _extract_headers
max_cols = max(
ValueError: max() iterable argument is empty
Impact
This is particularly problematic for technical documents containing patterns that get classified as table separators in non-table contexts. The error crashes the entire parsing pipeline — not just the bad table segment — so all hierarchical structure (headers, lists, code blocks) from the document is lost.
In my use case, ~15% of a 1,280-document corpus (189 files) hit this error, despite having rich heading structure that would otherwise parse fine.
Suggested Fix
Add a default parameter to the max() call and handle the empty case:
max_cols = max(
(len(row['tr']) for row in segment
if _is_table_row(row) and isinstance(row['tr'], dict)),
default=0,
)
if max_cols == 0:
# No valid table rows found — skip or convert to paragraphs
return {'paragraph': '---'} # or however you'd like to handle it
Environment
- markdown-to-data version: 2.0.1 (also verified unfixed in 2.0.2)
- Python 3.12
Bug Description
_extract_headersinmerge_table.pycrashes withValueError: max() iterable argument is emptywhen a table segment contains only separator rows (or rows whererow['tr']is a string rather than a dict).Root Cause
In
merge_table.pyline 25-28:The generator filters for rows where
row['tr']is adict, but when all rows in a segment haverow['tr']as a string (e.g.'table_separator'), the generator yields nothing andmax()raisesValueError.Minimal Reproducible Example
All of these crash:
In real-world documents this commonly happens with content like horizontal rules written as
---|---, or technical text near pipe characters that creates isolated separator-only segments.Full Traceback
Impact
This is particularly problematic for technical documents containing patterns that get classified as table separators in non-table contexts. The error crashes the entire parsing pipeline — not just the bad table segment — so all hierarchical structure (headers, lists, code blocks) from the document is lost.
In my use case, ~15% of a 1,280-document corpus (189 files) hit this error, despite having rich heading structure that would otherwise parse fine.
Suggested Fix
Add a
defaultparameter to themax()call and handle the empty case:Environment