# Extraction Result Error Structure Analysis ## Overview This document analyzes how errors and diagnostics are organized in the pdftract extraction result structure. ## ExtractionResult Structure The main `ExtractionResult` struct (defined in `crates/pdftract-core/src/extract.rs`) contains: ```rust pub struct ExtractionResult { pub fingerprint: String, pub pages: Vec, pub metadata: ExtractionMetadata, pub signatures: Vec, pub form_fields: Vec, pub links: Vec, pub attachments: Vec, pub threads: Vec, pub javascript_actions: Vec, } ``` ## Error Reporting Locations ### 1. Document-Level Diagnostics **Location**: `ExtractionResult.metadata.diagnostics: Vec` **Purpose**: Contains warnings and errors that affect the entire extraction process. **Examples**: - Tagged PDF detected (StructTree traversal deferred) - Xref repaired via forward scan - Coverage warnings - Page range errors ### 2. Per-Page Errors **Location**: `PageResult.error: Option` **Purpose**: Contains error messages when extraction fails for a specific page. **Structure**: ```rust pub struct PageResult { pub index: usize, pub page_number: u32, pub page_label: Option, pub width: Option, pub height: Option, pub rotation: Option, pub page_type: Option, pub spans: Vec, pub blocks: Vec, pub tables: Vec, pub annotations: Vec, pub error: Option, // ← Per-page error } ``` ### 3. Metadata Error Count **Location**: `ExtractionMetadata.error_count: usize` **Purpose**: Tracks the total number of pages that failed to extract. ## Internal Diagnostic Structure Before being converted to strings, diagnostics use the rich `Diagnostic` structure: ```rust pub struct Diagnostic { pub code: DiagCode, // Error type code pub byte_offset: Option, // Location in file pub object_ref: Option, // PDF object reference pub message: Cow<'static, str>, // Human-readable message } ``` ## Diagnostic Code Categories The `DiagCode` enum categorizes errors with prefixes: | Category | Prefix | Description | |----------|--------|-------------| | Structure | `STRUCT_*` | PDF structure errors (parser/object/document) | | Stream | `STREAM_*` | Stream decoder errors | | XREF | `XREF_*` | Cross-reference table errors | | Encryption | `ENCRYPTION_*` | Encryption-related errors | | Page | `PAGE_*` | Page-level errors | | Font | `FONT_*` | Font pipeline errors | | Graphics State | `GSTATE_*` | Graphics state errors | | Layout | `LAYOUT_*` | Layout and reading order errors | | OCR | `OCR_*` | OCR pipeline errors | | Remote | `REMOTE_*` | Remote source errors | | MCP | `MCP_*` | MCP server errors | | Cache | `CACHE_*` | Cache errors | | Security | `SECURITY_*` | Security-related diagnostics | ## Severity Levels Diagnostics have four severity levels: 1. **Info** — Does not affect output validity - Examples: `XREF_REPAIRED`, `TAGGED_PDF_STRUCT_TREE_DEFERRED` 2. **Warning** — Output is usable but degraded - Examples: `STRUCT_INVALID_NAME`, `FONT_GLYPH_UNMAPPED`, `STREAM_DECODE_ERROR` 3. **Error** — Output for this region/page is invalid; other regions OK - Examples: `STREAM_BOMB`, `PAGE_OUT_OF_RANGE`, `REMOTE_FETCH_INTERRUPTED` 4. **Fatal** — Extraction aborted, no usable output - Examples: `ENCRYPTION_UNSUPPORTED`, `REMOTE_TLS_FAILED`, `REMOTE_DNS_FAILED` ## Error Flow 1. **Emission**: During extraction, `Diagnostic` structs are emitted via the `emit!()` macro 2. **Collection**: Diagnostics are collected in `Vec` 3. **Conversion**: Before returning `ExtractionResult`, diagnostics are converted to strings: ```rust let diagnostics: Vec = coverage_result .diagnostics .iter() .map(|d| d.message.as_ref().to_string()) .collect(); ``` 4. **Exposure**: Final string messages are exposed in `ExtractionMetadata.diagnostics` ## Key Files - `crates/pdftract-core/src/extract.rs` - Main extraction pipeline, defines `ExtractionResult` - `crates/pdftract-core/src/diagnostics.rs` - Diagnostic system, defines `Diagnostic` and `DiagCode` - `src/graphics_state/diagnostics.rs` - Legacy diagnostic types (graphics state only) ## Example Diagnostic ```rust // Creating a diagnostic Diagnostic::with_static( DiagCode::StreamDecodeError, 12345, // byte offset "zlib stream truncated mid-inflation" ) // Converts to string in metadata: // "STREAM_DECODE_ERROR: zlib stream truncated mid-inflation (byte offset 12345)" ``` ## Acceptance Criteria Status ✅ **Error array structure understood** - Document-level diagnostics in `metadata.diagnostics` - Per-page errors in `PageResult.error` ✅ **Error fields documented** - Internal `Diagnostic` struct with code, offset, object_ref, message - Final string representation in extraction result ✅ **Relationship between errors and extraction phases clear** - Each diagnostic has a phase origin (e.g., "1.1", "1.5", "3.1") - DiagCode category prefixes indicate which layer emitted the error - Severity levels indicate impact on extraction result