firecrawl/pdf-inspector · critical

merge never returns OCR-only content

Error message

merge never returns OCR-only content

What it means

In choose_adaptive_content (src/vision/fusion.rs), merge_native_and_ocr is documented to only return Native or Fused; the PageContentSource::Ocr arm is an unreachable!('merge never returns OCR-only content'). Hitting it means the merge function violated its contract and returned OCR-only content — a library bug, not a user-triggerable condition. It aborts the thread with a panic rather than producing a catchable error.

Source

Thrown at src/vision/fusion.rs:510

            warning: format!(
                "kept higher-quality {} after comparing OCR",
                native.origin.description()
            ),
            recommend_hosted: false,
        };
    }

    let (markdown, source) = merge_native_and_ocr(native.markdown(), ocr);
    let warning = match source {
        PageContentSource::Native => format!(
            "kept trustworthy {} because OCR duplicated its content",
            native.origin.description()
        ),
        PageContentSource::Fused => format!(
            "fused trustworthy {} with complementary OCR",
            native.origin.description()
        ),
        PageContentSource::Ocr => unreachable!("merge never returns OCR-only content"),
    };
    AdaptiveContentChoice {
        markdown,
        source,
        warning,
        recommend_hosted: false,
    }
}

#[derive(Debug, Clone, Copy)]
struct ContentOverlap {
    shared_chars: usize,
}

fn content_overlap(first: &str, second: &str) -> ContentOverlap {
    let mut first_counts = BTreeMap::<char, usize>::new();
    for character in normalized_content_chars(first) {
        *first_counts.entry(character).or_insert(0) += 1;

View on GitHub (pinned to 636ca1a58b)

Solutions

  1. Revert or fix the change to merge_native_and_ocr so it can only return Native or Fused.
  2. If OCR-only output is now a legitimate outcome, replace the unreachable! with a real arm producing an Ocr warning instead of panicking.
  3. Add a unit test asserting merge_native_and_ocr never yields PageContentSource::Ocr for representative inputs.
  4. Reproduce with RUST_LOG=pdf_inspector::vision=debug and the failing PDF, then inspect the overlap/novelty values at the merge site.

Example fix

// before
PageContentSource::Ocr => unreachable!("merge never returns OCR-only content"),
// after
PageContentSource::Ocr => format!(
    "kept OCR content for {} (no trustworthy native text)",
    native.origin.description()
),
Defensive patterns

Strategy: type-guard

Validate before calling

// Library-side guard: assert the merge contract before formatting the warning
let source = merge_native_and_ocr(native.markdown(), ocr).1;
debug_assert!(matches!(source, PageContentSource::Native | PageContentSource::Fused));

Type guard

fn merge_source_is_valid(source: PageContentSource) -> bool {
    matches!(source, PageContentSource::Native | PageContentSource::Fused)
}

Try / catch

// Not user-catchable (panic). Library-side: replace unreachable! with a graceful arm
let warning = match source {
    PageContentSource::Ocr => {
        log::warn!("merge returned OCR-only content; treating as fused");
        "fused with OCR".to_string()
    }
    other => /* existing arms */
};

Prevention

When it happens

Trigger: Only reachable if merge_native_and_ocr's internal logic is changed/buggy and returns PageContentSource::Ocr; cannot be triggered by any external input through documented APIs.

Common situations: Developers modifying merge_native_and_ocr (e.g. changing the overlap/novelty thresholds or returning Ocr for low-overlap pages) break the invariant; downstream maintainers hitting it after a refactor of the fusion module.

Related errors


AI-assisted analysis of firecrawl/pdf-inspector@636ca1a58b (2026-09-05). Data as JSON: /api/errors/11bbbfbd0c17e46b. Report an issue: GitHub.