squidfunk/mkdocs-material · error · PluginError

Couldn't find font family '{family}' on Google Fonts ({res.s

Error message

Couldn't find font family '{family}' on Google Fonts ({res.status_code}: {res.reason})

What it means

`_fetch_font_from_google_fonts` downloads the font manifest from `https://fonts.google.com/download/list?family=...` when resolving a font family for social cards. Any non-200 response (font not found, rate limiting, network/proxy failure) raises this PluginError with the HTTP status and reason.

Source

Thrown at src/plugins/social/plugin.py:890

        # Fall back to regular font (guess if there are multiple)
        return self._resolve_font(family, fallback)

    # -------------------------------------------------------------------------

    # Fetch font family from Google Fonts
    def _fetch_font_from_google_fonts(self, family: str):
        path = os.path.join(self.config.cache_dir, "fonts")

        # Download manifest from Google Fonts - Google returns JSON with syntax
        # errors, so we just treat the response as plain text and parse out all
        # URLs to font files, as we're going to rename them anyway. This should
        # be more resilient than trying to correct the JSON syntax.
        url = f"https://fonts.google.com/download/list?family={family}"
        res = requests.get(url)

        # Ensure that the download succeeded
        if res.status_code != 200:
            raise PluginError(
                f"Couldn't find font family '{family}' on Google Fonts "
                f"({res.status_code}: {res.reason})"
            )

        # Extract font URLs from manifest
        for match in re.findall(
            r"\"(https:(?:.*?)\.[ot]tf)\"", str(res.content)
        ):
            with requests.get(match) as res:
                res.raise_for_status()

                # Construct image font for analysis by directly reading the
                # contents from the response without priorily writing to a
                # temporary file (like we did before), as this might lead to
                # problems on Windows machines, see https://t.ly/LiF_k
                with BytesIO(res.content) as f:
                    font = ImageFont.truetype(f)

View on GitHub (pinned to e2136532f4)

Solutions

  1. Verify the font family name exists on fonts.google.com and use its exact name (spaces encoded).
  2. For custom/local fonts, place the font files in the cache directory yourself or use a layout that references a bundled font instead of Google Fonts.
  3. Fix network egress: configure HTTPS_PROXY, allow fonts.google.com in the firewall, or pre-populate the plugin's font cache.
  4. Retry the build if the failure was a transient 429/5xx; add caching of downloaded fonts between CI runs.

Example fix

# before (mkdocs.yml, font not on Google Fonts)
- social:
    cards_font: My Corporate Sans

# after: use a Google-hosted family or bundle locally
- social:
    cards_font: Roboto
Defensive patterns

Strategy: retry

Validate before calling

# preflight: fonts reachable and family known
def font_available(family):
    import requests
    r = requests.head(f"https://fonts.google.com/download/list?family={family}", timeout=10)
    return r.status_code == 200

Try / catch

from mkdocs.exceptions import PluginError
import time
for attempt in range(3):
    try:
        return plugin._resolve_font(family, style)
    except PluginError as e:
        if ' 429' in str(e) or ' 50' in str(e):
            time.sleep(2 ** attempt)
            continue
        raise

Prevention

When it happens

Trigger: A card layout requests a font family not available on Google Fonts; no network access or a blocking proxy/firewall; Google Fonts returns 403/429 (rate limit or bot protection); family name misspelled or using a non-Google-Fonts font.

Common situations: CI environments without internet egress; corporate proxies blocking fonts.google.com; custom `cards_font` set to a self-hosted/local font that Google doesn't serve; transient 429s during batch builds.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of squidfunk/mkdocs-material@e2136532f4 (2026-08-29). Data as JSON: /api/errors/4df56e8d0c95830d. Report an issue: GitHub.