---
title: "Where PDF parsers fail: Docling vs. Nutrient on three real documents"
canonical_url: "https://www.nutrient.io/blog/pdf-extraction-document-case-studies/"
md_url: "https://www.nutrient.io/blog/pdf-extraction-document-case-studies.md"
last_updated: "2026-08-01T02:04:12.735Z"
description: "Side-by-side Docling and Nutrient output on three real-world PDFs from opendataloader-bench — heading demotion, TOC misclassification, and table header absorption, with the downstream cost of each failure."
---

Aggregate accuracy scores describe how parsers perform across 200 documents, but what they don’t show is what failure looks like in a specific document — and what that failure costs downstream.

This article examines three documents from the [opendataloader-bench corpus](https://github.com/opendataloader-project/opendataloader-bench) where extraction engines diverge. Each example isolates a different failure mode: a misread table of contents, heading hierarchy in a textbook page, and table structure in a regulatory report. For each, the ground truth annotation, Nutrient’s output, and Docling’s output are compared — along with the downstream consequence of getting it wrong.

For methodology, metrics, and full benchmark results, read [How we test PDF extraction: The opendataloader-bench benchmark](https://www.nutrient.io/blog/pdf-extraction-benchmark-opendataloader-bench.md).

## A course’s table of contents misread as a table

**Document:** This is the table of contents (TOC) page of a Mohave Community College BIO181 biology course workbook — a 92-page document spanning genetics, cell biology, and lab exercises. The TOC uses dot-leader formatting (section titles followed by dotted lines and page numbers) to list 30+ entries. Course materials of this type appear regularly in educational technology and content digitization pipelines.

**Why it’s difficult:** Parsers that identify tabular structure by column alignment can misread dot-leader rows as table cells, wrapping the entire TOC in a markdown table. As a result, the opening heading can be demoted or lost.

**Ground truth:** College and course identifiers appear as plain text, followed by a `# Table of Contents` H1 heading, with all entries appearing as plain text dot-leader rows.

**Nutrient output (default engine):** Produces the correct plain-text TOC with a college header and `# Table of Contents` as H1. Score: 0.998 overall.

**Docling output:** Demotes the heading from H1 to H2 and wraps every TOC entry in a single-column markdown table — a structure that doesn’t exist in the source. Score: 0.787 overall (MHS 0.699).

```

## Table of Contents

| Measurement Lab worksheet...................................................................................... 3           |
|-----------------------------------------------------------------------------------------------------------------------------|
| Scientific Method Lab.................................................................................................. 6   |
| Chemistry of the Cell ~ But this is biology!........................................... 9                                   |
| Biological Macromolecules and Their Indicators............................. 10                                              |
| Worksheet for Chemistry of the Cell....................................................... 12                               |...

```

The heading demotion (H2 instead of H1) directly drives the Markdown Heading Score (MHS) gap. A pipeline that uses heading depth to classify document landmarks will treat the Table of Contents as a subsection rather than a top-level navigational element. The spurious table wrapping compounds the problem: A schema that expects plain text rows receives a single-column table instead, silently breaking any downstream step that relies on that field’s type.

## Heading hierarchy in an astronomy textbook

**Document:** This is a page from an OpenStax astronomy chapter covering Earth’s position in the solar system. The page opens with a section title and closes with a figure caption that also functions as a subsection heading. Open-access academic texts like OpenStax are common source documents in scientific RAG systems and educational platforms.

**Why it’s difficult:** The second heading — “Earth and Moon, Drawn to Scale” — appears directly below a figure and can be read as a caption rather than a new section. Tools that rely on font size alone may treat it as body text or assign it the wrong heading level.

**Ground truth:** Two headings appear at H1 — “Humanity’s Home Base” and “Earth and Moon, Drawn to Scale.”

**Nutrient output (default engine):** Both headings are correctly identified and structured. Score: 1.000 overall (MHS 1.000).

**Docling output:** Demotes the first heading from H1 to H2 and misses the second heading entirely — rendering “Earth and Moon, Drawn to Scale” as plain body text. Score: 0.773 overall (MHS 0.585).

```

## Humanity’s Home Base.

Figure 1. This image shows the Western hemisphere as viewed
from space 35,400 kilometers (about 22,000 miles) above Earth.
Data about the land surface from one satellite was combined with
another satellite’s data about the clouds to create the image.
(credit: modification of work by R. Stockli, A. Nelson, F. Hasler,
NASA/ GSFC/ NOAA/ USGS)

Our nearest astronomical neighbor is Earth’s satellite, commonly
called the Moon. Figure 2 shows Earth and the Moon drawn to scale...

Earth and Moon, Drawn to Scale.

```

In a retrieval system, a missing heading means the content under it can’t be navigated to directly. Any query targeting the figure-and-scale comparison section must scan the full document rather than routing to the correct node in the heading tree. The failure isn’t visible in the extracted text itself — the words are present — but the structural signal that downstream systems rely on for chunking and retrieval is gone.

## Table structure in a Philippine ports regulatory report

**Document:** This is a page from a regulatory research report on invasive aquatic species risk at Philippine ports. The page contains a shipcall statistics table listing foreign and domestic traffic counts for 10 ports. Regulatory and government reports with visually complex tables are standard inputs for compliance, risk, and financial due diligence pipelines.

**Why it’s difficult:** The table uses a two-level visual header: “PORT” and “SHIPCALLS” appear as labels above the table, with “Foreign” and “Domestic” as the actual column subheaders inside it. A parser that treats these visual labels as table header cells produces a structurally incorrect representation.

**Ground truth:** The table has three columns, with a header row (empty, Foreign, Domestic) and 10 data rows.

**Nutrient output (default engine):** Produces the correct three-column structure with a header row matching ground truth. Score: 1.000 TEDS, 0.976 overall.

**Docling output:** Absorbs the visual labels into the table header row, producing “PORT | SHIPCALLS | SHIPCALLS” as the first row — a structurally incorrect three-column header that doesn’t match the ground truth schema. Score: 0.920 overall (TEDS 0.918).

```

| PORT           | SHIPCALLS   | SHIPCALLS   |
|----------------|-------------|-------------|
|                | Foreign     | Domestic    |
| MANILA         | 3,047       | 38,476      |
| BATANGAS       | 612         | 10,428      |
| CEBU           | 1,170       | 21,799      |...

```

The downstream consequence is a column mismatch. Any workflow joining on column names — “Which value is Foreign shipcalls for CEBU?” — maps to the wrong column if the header row is wrong. The data is present; the structural error is invisible until a query returns a value from the wrong column.

## What these failures have in common

These three examples share a pattern: The extracted text is largely correct, but the structural interpretation is wrong. Dot-leader rows become tables. Headings get demoted or dropped. Visual label rows become data columns. None of these failures produces an obvious error — they pass character-level checks and only surface when downstream systems depend on the structure to navigate, join, or chunk the content.

Across all three documents, Nutrient’s default engine avoided the failure and Docling did not:

| Document                 | Nutrient | Docling |
| ------------------------ | -------- | ------- |
| Course table of contents | 0.998    | 0.787   |
| Astronomy textbook       | 1.000    | 0.773   |
| Ports regulatory report  | 0.976    | 0.920   |

The aggregate scores in the [benchmark](https://www.nutrient.io/blog/pdf-extraction-benchmark-opendataloader-bench.md) reflect this: small overall gaps between tools that can correspond to large functional differences on specific document types.

**ParseBench:** Nutrient’s agentic extraction mode ranks #12 of 84 providers on the public ParseBench leaderboard (score: 70.1), ahead of Extend 2.0 and most general-purpose AI models. Content faithfulness: 83.4. Visual grounding: 76.2. ParseBench is published by LlamaParse and uses a different corpus and metrics from opendataloader-bench.

[View full benchmark results](https://www.nutrient.io/api/data-extraction-api/benchmarks/)

Teams evaluating PDF parsers for production use can run the [opendataloader-bench harness](https://github.com/opendataloader-project/opendataloader-bench) against any parser on their own document sample. For schema-driven extraction with per-field citations and bounding boxes — making structural errors like these observable per field before data enters a pipeline — see the [Nutrient Data Extraction API](https://www.nutrient.io/api/data-extraction-api/).
---

## Related pages

- [The business case for accessibility: Five ways it drives enterprise value](/blog/5-ways-accessibility-drives-enterprise-value.md)
- [Accessibility Untangled Why It Matters Guide](/blog/accessibility-untangled-why-it-matters-guide.md)
- [Advanced Techniques For React Native Ui Components](/blog/advanced-techniques-for-react-native-ui-components.md)
- [`vector_store` holds your indexed documents (see the multimodal RAG post](/blog/agentic-rag.md)
- [Ai Document Automation Extraction To Action](/blog/ai-document-automation-extraction-to-action.md)
- [Ai Legal Assistant Document Authoring](/blog/ai-legal-assistant-document-authoring.md)
- [Angular File Viewer Pdf Image Office Files](/blog/angular-file-viewer-pdf-image-office-files.md)
- [Auto Tagging And Document Accessibility In Dotnet Sdk](/blog/auto-tagging-and-document-accessibility-in-dotnet-sdk.md)
- [Best Document Viewers](/blog/best-document-viewers.md)
- [The CEO’s AI playbook: Why decision architecture beats model selection](/blog/ceo-ai-playbook-decision-architecture.md)
- [1. Extract and chunk the PDF.](/blog/chat-with-pdf.md)
- [Complete Guide To Pdfjs](/blog/complete-guide-to-pdfjs.md)
- [Construction Document Data Extraction](/blog/construction-document-data-extraction.md)
- [Convert One Drive Files To Pdf In Sharepoint](/blog/convert-one-drive-files-to-pdf-in-sharepoint.md)
- [Create And Edit Pdfs In Flutter](/blog/create-and-edit-pdfs-in-flutter.md)
- [Create Pdfs With React](/blog/create-pdfs-with-react.md)
- [Creating A Document Scanner With Ocr In Python](/blog/creating-a-document-scanner-with-ocr-in-python.md)
- [Creating And Filling Pdf Forms Programmatically In Javascript](/blog/creating-and-filling-pdf-forms-programmatically-in-javascript.md)
- [The CTO’s AI playbook: Why accountability architecture beats orchestration](/blog/cto-ai-playbook-accountability-architecture.md)
- [Digital Signatures](/blog/digital-signatures.md)
- [Digital Workflow Automation](/blog/digital-workflow-automation.md)
- [Document Ai Vs Ocr](/blog/document-ai-vs-ocr.md)
- [Document Viewer](/blog/document-viewer.md)
- [Document Watermarking](/blog/document-watermarking.md)
- [Emerging threats: Your logging system may be an agentic threat vector](/blog/emerging-threats-your-logging-system.md)
- [app.py](/blog/extract-text-from-pdf-using-python.md)
- [Fillable Pdf](/blog/fillable-pdf.md)
- [How To Add Digital Signature To Pdf Using React](/blog/how-to-add-digital-signature-to-pdf-using-react.md)
- [How To Build A Dotnet Maui Pdf Viewer](/blog/how-to-build-a-dotnet-maui-pdf-viewer.md)
- [How To Build A Flutter Pdf Viewer](/blog/how-to-build-a-flutter-pdf-viewer.md)
- [or](/blog/how-to-build-a-javascript-pdf-viewer-with-pdfjs.md)
- [How To Build A Javascript Pdf Viewer](/blog/how-to-build-a-javascript-pdf-viewer.md)
- [or](/blog/how-to-build-a-nextjs-pdf-viewer.md)
- [How To Build A Powerpoint Viewer Using Javascript](/blog/how-to-build-a-powerpoint-viewer-using-javascript.md)
- [Using Yarn](/blog/how-to-build-a-react-excel-viewer.md)
- [How To Build A React Native Pdf Viewer](/blog/how-to-build-a-react-native-pdf-viewer.md)
- [How To Build A React Powerpoint Viewer](/blog/how-to-build-a-react-powerpoint-viewer.md)
- [How To Build A Reactjs File Viewer](/blog/how-to-build-a-reactjs-file-viewer.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer-with-react-pdf.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer.md)
- [How To Build A Reactjs Viewer With Pdfjs](/blog/how-to-build-a-reactjs-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer With Pdfjs](/blog/how-to-build-a-vuejs-pdf-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer](/blog/how-to-build-a-vuejs-pdf-viewer.md)
- [How To Build An Android Pdf Viewer](/blog/how-to-build-an-android-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Ng2 Pdf Viewer](/blog/how-to-build-an-angular-pdf-viewer-with-ng2-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Pdfjs](/blog/how-to-build-an-angular-pdf-viewer-with-pdfjs.md)
- [How To Convert Docx To Pdf Using Javascript](/blog/how-to-convert-docx-to-pdf-using-javascript.md)
- [How To Convert Docx To Pdf Using Python](/blog/how-to-convert-docx-to-pdf-using-python.md)
- [How To Convert Html To Pdf Using Html2pdf](/blog/how-to-convert-html-to-pdf-using-html2pdf.md)
- [or](/blog/how-to-convert-html-to-pdf-using-react.md)
- [or](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-python.md)
- [How To Convert Word To Pdf In Nodejs](/blog/how-to-convert-word-to-pdf-in-nodejs.md)
- [or](/blog/how-to-create-a-react-js-signature-pad.md)
- [How To Create Pdfs With React To Pdf](/blog/how-to-create-pdfs-with-react-to-pdf.md)
- [How To Edit Pdfs Using Ios Pdf Library](/blog/how-to-edit-pdfs-using-ios-pdf-library.md)
- [How To Embed A Pdf Viewer In Your Website](/blog/how-to-embed-a-pdf-viewer-in-your-website.md)
- [How To Extract Tables From Pdf And Images](/blog/how-to-extract-tables-from-pdf-and-images.md)
- [How To Generate Pdf From Html With Nodejs](/blog/how-to-generate-pdf-from-html-with-nodejs.md)
- [base_url tells WeasyPrint where to resolve relative asset paths](/blog/how-to-generate-pdf-reports-from-html-in-python.md)
- [Open an image.](/blog/how-to-use-tesseract-ocr-in-python.md)
- [From an HTML string.](/blog/html-in-pdf-format.md)
- [Javascript Pdf Libraries](/blog/javascript-pdf-libraries.md)
- [Linearized Pdf](/blog/linearized-pdf.md)
- [Swift Package Manager](/blog/mobile-pdf-sdk.md)
- [`elements` come from your document parser — each has a type and content.](/blog/multimodal-rag.md)
- [Nutrient Vs Conga Composer](/blog/nutrient-vs-conga-composer.md)
- [Online Document Viewer](/blog/online-document-viewer.md)
- [Open Pdf In Your Web App](/blog/open-pdf-in-your-web-app.md)
- [Building WCAG 2.2, Section 508, and PDF/UA-compliant PDFs with an SDK](/blog/pdf-accessibility.md)
- [Pdf Extraction Benchmark Opendataloader Bench](/blog/pdf-extraction-benchmark-opendataloader-bench.md)
- [Pdf Page Labels](/blog/pdf-page-labels.md)
- [Pdf Sdk Compliance Security Checklist](/blog/pdf-sdk-compliance-security-checklist.md)
- [Pdf Sdk Performance Benchmark](/blog/pdf-sdk-performance-benchmark.md)
- [Pdf Ua Compliance Guide](/blog/pdf-ua-compliance-guide.md)
- [Pdfjs Advanced Loading Streaming Workers](/blog/pdfjs-advanced-loading-streaming-workers.md)
- [Pdfjs Annotation Editor Layer](/blog/pdfjs-annotation-editor-layer.md)
- [Pdfjs Area Annotations Canvas Capture](/blog/pdfjs-area-annotations-canvas-capture.md)
- [Pdfjs Coordinate Systems Pdf To Screen](/blog/pdfjs-coordinate-systems-pdf-to-screen.md)
- [Pdfjs Document Outline Bookmarks Metadata](/blog/pdfjs-document-outline-bookmarks-metadata.md)
- [Pdfjs Eventbus Guide](/blog/pdfjs-eventbus-guide.md)
- [Pdfjs Limitations Commercial Upgrade](/blog/pdfjs-limitations-commercial-upgrade.md)
- [Pdfjs Native Annotation Layer Forms](/blog/pdfjs-native-annotation-layer-forms.md)
- [Pdfjs Navigation Zoom Rotation](/blog/pdfjs-navigation-zoom-rotation.md)
- [Pdfjs Pdf Page Manipulation Pdf Lib](/blog/pdfjs-pdf-page-manipulation-pdf-lib.md)
- [Pdfjs React Viewer Setup](/blog/pdfjs-react-viewer-setup.md)
- [Pdfjs Rendering Overlays React Portals](/blog/pdfjs-rendering-overlays-react-portals.md)
- [Pdfjs Server Side Text Extraction](/blog/pdfjs-server-side-text-extraction.md)
- [Pdfjs Sticky Note Annotations](/blog/pdfjs-sticky-note-annotations.md)
- [Pdfjs Text Highlight Annotations](/blog/pdfjs-text-highlight-annotations.md)
- [Pdfjs Text Search Pdffindcontroller](/blog/pdfjs-text-search-pdffindcontroller.md)
- [Pdfjs Thumbnail Sidebar](/blog/pdfjs-thumbnail-sidebar.md)
- [Process Flows](/blog/process-flows.md)
- [React Native Pdf Annotation](/blog/react-native-pdf-annotation.md)
- [or](/blog/sample-blog-updated.md)
- [Add DWS MCP Server to your Claude Code project.](/blog/teaching-llms-to-read-pdfs.md)
- [Open an image file.](/blog/tesseract-python-guide.md)
- [Top 5 Javascript Pdf Viewers](/blog/top-5-javascript-pdf-viewers.md)
- [Convert an HTML file to PDF.](/blog/top-ten-ways-to-convert-html-to-pdf.md)
- [Vector Pdf](/blog/vector-pdf.md)
- [Wcag2 Accessibility Requirements Documents](/blog/wcag2-accessibility-requirements-documents.md)
- [Web Sdk Is Now Headless](/blog/web-sdk-is-now-headless.md)
- [What Are Annotations](/blog/what-are-annotations.md)
- [What Is A Vpat](/blog/what-is-a-vpat.md)
- [What Is Document Processing](/blog/what-is-document-processing.md)
- [What Is Pdf Ua](/blog/what-is-pdf-ua.md)
- [Why Pdfium Is A Trusted Platform For Pdf Rendering](/blog/why-pdfium-is-a-trusted-platform-for-pdf-rendering.md)
- [Why Your Ai Agent Hallucinates Pdf Table Data](/blog/why-your-ai-agent-hallucinates-pdf-table-data.md)

