ocrmypdf/OCRmyPDF · warning · NotImplementedError

SystemFontProvider does not provide a fallback font. Use Bui

Error message

SystemFontProvider does not provide a fallback font. Use BuiltinFontProvider for Occulta.ttf fallback.

What it means

SystemFontProvider enumerates fonts installed on the OS; it deliberately does not ship or resolve the glyphless 'Occulta' fallback used for invisible OCR text, so get_fallback_font() always raises NotImplementedError, directing you to BuiltinFontProvider.

Source

Thrown at src/ocrmypdf/font/system_font_provider.py:560

        """Get list of font names this provider can potentially find.

        Note: This returns all font names we know patterns for, not
        necessarily fonts that are actually installed. Use get_font()
        to check if a specific font is available.

        Returns:
            List of logical font names
        """
        return list(self.NOTO_FONT_PATTERNS.keys())

    def get_fallback_font(self) -> FontManager:
        """Get the glyphless fallback font.

        Raises:
            NotImplementedError: System provider doesn't provide fallback.
                Use BuiltinFontProvider for the fallback font.
        """
        raise NotImplementedError(
            "SystemFontProvider does not provide a fallback font. "
            "Use BuiltinFontProvider for Occulta.ttf fallback."
        )

View on GitHub (pinned to 5074a0b0e1)

Solutions

  1. Use BuiltinFontProvider (bundled Occulta.ttf) for the fallback font.
  2. If iterating a chain, treat NotImplementedError as 'skip this provider' rather than an error.

Example fix

# before
fallback = system_font_provider.get_fallback_font()
# after
fallback = BuiltinFontProvider(builtin_font_dir).get_fallback_font()
Defensive patterns

Strategy: type-guard

Validate before calling

from ocrmypdf.font.builtin_font_provider import BuiltinFontProvider
if isinstance(provider, SystemFontProvider):
    fallback = BuiltinFontProvider(...).get_fallback_font()
else:
    fallback = provider.get_fallback_font()

Type guard

def provider_has_fallback(provider) -> bool:
    return not provider.__class__.__name__.startswith('System')  # or check explicitly

Try / catch

try:
    provider.get_fallback_font()
except NotImplementedError:
    provider = BuiltinFontProvider(...); fallback = provider.get_fallback_font()

Prevention

When it happens

Trigger: Calling SystemFontProvider.get_fallback_font() directly, or a chain that surfaces the exception when fallback handling isn't configured to skip it.

Common situations: Custom font code assuming any provider can yield a fallback; catching only some exception types so NotImplementedError escapes.

Related errors


AI-assisted analysis of ocrmypdf/OCRmyPDF@5074a0b0e1 (2026-08-27). Data as JSON: /api/errors/7b54e61399cd03ae. Report an issue: GitHub.