docling-project/docling · error · DocumentLoadError
Legacy Box Notes (the pre-August-2022 atext/pool format) are
Error message
Legacy Box Notes (the pre-August-2022 atext/pool format) are not supported yet; only the current Box Note format can be converted.
What it means
The second post-conversion assertion in _run_benchmark(): after confirming exactly one table, it checks that the table's data grid is merge_count rows by 4 columns, matching the generated workbook (one merged A:C range plus a value in D per row, no header row). It fires when Docling's XLSX parsing returns a different grid: extra/missing rows (e.g. a header row added, empty trailing rows included) or different column count (merged A:C collapsed to one column instead of expanded to three, or an extra index column). It signals that the merged-cell expansion semantics assumed by the benchmark no longer hold.
Source
Thrown at docling/backend/boxnote_backend.py:69
self.data: dict[str, Any] = {}
try:
raw = ""
if isinstance(self.path_or_stream, BytesIO):
raw = self.path_or_stream.getvalue().decode("utf-8")
elif isinstance(self.path_or_stream, Path):
raw = self.path_or_stream.read_text(encoding="utf-8")
if raw.strip():
loaded = json.loads(raw)
if isinstance(loaded, dict):
self.data = loaded
except (json.JSONDecodeError, UnicodeDecodeError, OSError) as e:
raise DocumentLoadError(
f"Could not load Box Note document with hash {self.document_hash}."
) from e
if "atext" in self.data and not self.is_valid():
raise DocumentLoadError(
"Legacy Box Notes (the pre-August-2022 atext/pool format) are not "
"supported yet; only the current Box Note format can be converted."
)
@override
def is_valid(self) -> bool:
return isinstance(self.data.get("doc"), dict)
@classmethod
@override
def supports_pagination(cls) -> bool:
return False
@classmethod
@override
def supported_formats(cls) -> set[InputFormat]:
return {InputFormat.BOXNOTE}
View on GitHub (pinned to 61d76f1ff3)
Solutions
- Inspect table.data.grid (or export the document to HTML/markdown) to see the actual shape: num_cols == 2 means merged ranges are collapsed rather than expanded; num_rows == merge_count + 1 means a header row was added.
- Update the assertion to the current backend contract, e.g. `if table.data.num_rows != merge_count + 1` if headers are now emitted, or `num_cols != 2` if merges are collapsed — and update non_empty_cells / rectangle_area bookkeeping in BenchmarkResult to match.
- Pin the benchmark to the docling version whose merged-cell expansion (A:C expanded to 3 columns, 4 total) you intend to measure, e.g. run inside the repo checkout with `uv run python perfs/xlsx_merged_cells.py`.
- If the change is unintended (a regression in merged-cell expansion), fix the XLSX backend so num_cols stays 4 and num_rows equals merge_count, keeping the benchmark as the regression guard.
Example fix
// before (perfs/xlsx_merged_cells.py:153-156)
if table.data.num_rows != merge_count or table.data.num_cols != 4:
raise RuntimeError(
f"unexpected table dimensions: {table.data.num_rows}x{table.data.num_cols}"
)
// after - encode the backend's actual contract explicitly
EXPECTED_COLS = 4 # A:C merged range expanded to 3 columns + column D
header_offset = 1 if table.data.num_rows == merge_count + 1 else 0
if table.data.num_cols != EXPECTED_COLS:
raise RuntimeError(
f"unexpected column count: {table.data.num_cols} != {EXPECTED_COLS}"
)
if table.data.num_rows - header_offset != merge_count:
raise RuntimeError(
f"unexpected row count: {table.data.num_rows} != {merge_count}"
) Defensive patterns
Strategy: validation
Validate before calling
table = document.tables[0]
num_rows, num_cols = table.data.num_rows, table.data.num_cols
# generated workbook: merge_count rows (A:C merged per row) + column D, no header
if num_cols not in (4,): # extend if the backend collapses merges (2) or adds columns
print(f"column count changed: {num_cols}", file=sys.stderr)
row_delta = num_rows - merge_count
if row_delta not in (0, 1): # 1 == backend now emits a header row
print(f"row count off by {row_delta}", file=sys.stderr) Type guard
def table_matches_workbook(table, merge_count: int, num_cols: int = 4) -> bool:
"""True when the parsed table grid matches the generated merged-range workbook."""
return (
table is not None
and table.data is not None
and table.data.num_rows == merge_count
and table.data.num_cols == num_cols
) Try / catch
if not table_matches_workbook(table, merge_count):
# keep the sweep alive but flag the row/col deviation for triage
tqdm.write(
f"dimension drift for merge_count={merge_count}: "
f"{table.data.num_rows}x{table.data.num_cols}",
file=sys.stderr,
) Prevention
- After any docling / docling-core / openpyxl upgrade, dump one converted workbook (document.export_to_html() or table.data.grid) and eyeball the grid before running the full benchmark matrix.
- Keep the workbook generator (_create_workbook) and the dimension assertion in the same change set: if one changes, change the other and the BenchmarkResult bookkeeping (non_empty_cells, rectangle_area) too.
- Record docling_version and commit_sha with every result (already done) so a dimension failure can be bisected to the exact backend change.
When it happens
Trigger: A Docling version change in how the XLSX backend expands merged ranges into the table grid (collapsing merged cells to a single column yields num_cols == 2 instead of 4); the backend adding a header row or omitting all-empty rows (num_rows becomes merge_count + 1 or fewer); openpyxl/docling-core TableData changes to num_rows/num_cols accounting; benchmarking a branch where cell-level dedup or row-span handling changed.
Common situations: Running the perf harness across a Docling upgrade to compare performance without updating the structural expectations first; a PR that changes MsDocumentBackend merged-cell handling; benchmark results invalidated because the assertion encodes the exact grid contract of one specific docling-core version; running against an installed docling older/newer than the checkout.
Related errors
- Could not load Box Note document with hash {self.document_ha
- Could not initialize AsciiDoc backend for file with hash {se
AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14).
Data as JSON: /api/errors/e1186e0bed7e0c86.
Report an issue: GitHub.