MadsLorentzen/ai-job-search · error · VerificationError

text layer is missing required text: {required!r} (extractor

Error message

text layer is missing required text: {required!r} (extractor: {extractor})

What it means

Raised when one of the required_text strings cannot be found in the PDF's normalized text layer. Both the extracted text and the required snippet are whitespace-normalized, so the failure means the wording genuinely differs, not merely line-break formatting.

Source

Thrown at tools/verify_pdf.py:125

            raise VerificationError(
                f"could not write --dump-text to {dump_path}: {exc}"
            ) from exc

    if expected_pages is not None and actual_pages != expected_pages:
        raise VerificationError(
            f"expected {expected_pages} page(s), found {actual_pages} (extractor: {extractor})"
        )

    normalized = normalize_text(extracted_text)
    if len(normalized) < min_chars:
        raise VerificationError(
            f"text layer has {len(normalized)} character(s); expected at least {min_chars} "
            f"(extractor: {extractor})"
        )

    for required in required_text:
        if normalize_text(required) not in normalized:
            raise VerificationError(
                f"text layer is missing required text: {required!r} (extractor: {extractor})"
            )
    return extractor, extracted_text, actual_pages


def build_parser():
    parser = argparse.ArgumentParser(
        description="Verify a PDF's page count and ATS-readable text layer."
    )
    parser.add_argument("pdf", type=Path, help="PDF file to verify")
    parser.add_argument("--pages", type=int, help="required exact page count")
    parser.add_argument(
        "--min-chars",
        type=int,
        default=1,
        help="minimum non-whitespace text-layer characters (default: 1)",
    )
    parser.add_argument(

View on GitHub (pinned to 79cd383e58)

Solutions

  1. Dump the extracted text (use dump_text/--dump-text or pdftotext) and search for the closest actual wording; update required_text to match
  2. Fix the generator so the expected literal actually appears in the text layer
  3. Normalize unicode on your side (e.g. unicodedata.normalize('NFKC') on both sides) or choose required snippets without ligatures/smart punctuation
  4. If the phrase only exists as an image, add OCR or drop that required_text entry

Example fix

# before
verify_pdf(pdf, required_text=('Total: 1,234.50',))
# after — match actual localized formatting in the text layer
verify_pdf(pdf, required_text=('Total:', '1.234,50'))
Defensive patterns

Strategy: validation

Validate before calling

import subprocess
norm = lambda s: ' '.join(s.split())
text = norm(subprocess.run(['pdftotext', str(pdf), '-'], capture_output=True, text=True).stdout)
missing = [r for r in required if norm(r) not in text]
assert not missing, f'will fail verification: {missing}'

Try / catch

try:
    verify_pdf(pdf, required_text=required)
except VerificationError as e:
    if 'missing required text' in str(e):
        dump_and_diff(pdf, required)  # inspect actual wording, then adjust

Prevention

When it happens

Trigger: Calling verify_pdf(path, required_text=('Invoice Total',)) where that phrase (after whitespace collapsing) does not appear: dynamic content differs from the expected literal, unicode/ligature differences, hyphenation splitting words, or the phrase living in an image rather than the text layer.

Common situations: Template wording changed but the verification literal was not updated; localized date/currency formatting differences; ligatures (fi/fl) or smart quotes in extracted text; required text rendered inside an embedded image or SVG.

Related errors


AI-assisted analysis of MadsLorentzen/ai-job-search@79cd383e58 (2026-08-27). Data as JSON: /api/errors/108a2dc4f29b01bd. Report an issue: GitHub.