How to fix the PDF/A font embedding validation error

PDF/A requires that all fonts used in a document are fully embedded. If any font is referenced by name but not embedded, validation fails. This is one of the most common PDF/A conversion errors.
ValidationError::FontNotEmbedded
PDF/A-1b validation failed: font 'Arial' is not embedded

Why this happens

The document references a system font by name

The PDF contains text that uses a font installed on the system (like Arial or Times New Roman) but does not embed the font data. This is valid in regular PDF but not in PDF/A: the archive standard requires all fonts to be self-contained within the file.

Partial font embedding

Some tools embed only the glyph subset actually used in the document. If the subset table is missing required metadata (like the Widths array or BaseFont entries), PDF/A validators reject the font as insufficiently embedded.

Type1 font without required metrics

Type1 fonts require a FontDescriptor with specific metric entries (Ascent, Descent, CapHeight) to be PDF/A compliant. Older documents often omit these.

How to fix it

  1. Embed fonts before converting to PDF/A

    Call embed_fonts() on the document before running the PDF/A conversion. This scans all font references and embeds the data from your system font directories.

    code
    use pdfluent::{PdfDocument, PdfAProfile};
    
    let mut doc = PdfDocument::open("report.pdf")?;
    
    // Embed all referenced fonts
    doc.embed_fonts()?;
    
    // Now convert to PDF/A-1b
    doc.convert_to_pdfa(PdfAProfile::A1b)?;
    
    let report = doc.validate_pdfa(PdfAProfile::A1b)?;
    println!("Valid: {}", report.is_valid());
    
    doc.save("report_pdfa.pdf")?;
  2. Use font subsetting to reduce file size while staying compliant

    Embedding full fonts increases file size. Use subset embedding to include only the glyphs present in the document. PDFluent's embed_fonts_subset() produces a valid PDF/A-compliant subset.

    code
    use pdfluent::{PdfDocument, PdfAProfile, FontSubsetReport};
    
    let mut doc = PdfDocument::open("report.pdf")?;
    
    // Font subsetting is available in 1.0; arbitrary font embedding
    // (`embed_font`) is deferred — returns Error::MissingDependency.
    doc.subset_fonts()?;
    
    doc.convert_to_pdfa(PdfAProfile::A2b)?;
    doc.save("report_pdfa.pdf")?;
  3. Use auto-embed during PDF/A conversion

    Pass EmbedFonts::Auto to convert_to_pdfa_options(). This embeds all missing fonts in a single pass. Slower than pre-embedding but requires fewer steps.

    code
    use pdfluent::{PdfDocument, PdfAProfile, PdfaConvertOptions, EmbedFonts};
    
    let mut doc = PdfDocument::open("report.pdf")?;
    
    doc.convert_to_pdfa_options(PdfAProfile::A1b, PdfaConvertOptions {
        embed_fonts: EmbedFonts::Auto,
        ..Default::default()
    })?;
    
    doc.save("report_pdfa.pdf")?;

Frequently asked questions

Which fonts are most commonly missing?
Arial, Times New Roman, Helvetica, and Courier are system fonts that applications reference without embedding. PDF/A requires embedding all of them, including standard Type1 fonts like Helvetica.
Can I validate PDF/A without converting?
Yes. Document::validate_pdfa() runs validation only and returns a report with all violations. Use this to check an existing file before deciding whether to convert.
What is the difference between PDF/A-1b and PDF/A-2b?
PDF/A-1b is the basic visual reproduction level based on PDF 1.4. PDF/A-2b is based on PDF 1.7 and adds JPEG 2000 compression and optional content. Font embedding requirements are the same across both levels.
The font is embedded but the error still appears.
Check that the font embedding is complete. Run validate_pdfa() and inspect the full error list. Partial embedding (missing Widths array or FontDescriptor) triggers a different but related error.