ScreenshotNeo

BlogHow-to

wkhtmltopdf cannot load font: how to fix missing web fonts

Diagnose missing fonts in wkhtmltopdf PDFs by checking glyph coverage, Fontconfig, web-font paths, and the runtime environment.

By the ScreenshotNeo team4 October 20268 min read

If wkhtmltopdf substitutes or omits a web font, diagnose the machine that actually creates the PDF. Check, in order: whether the installed font contains the needed glyphs, whether Fontconfig can see the font and its configuration, whether the CSS font asset loads from the renderer, and whether production uses the same wkhtmltopdf build and environment as local development. UTF-8 settings can fix text decoding; they cannot install a font or add missing glyphs.

The exact remedy depends on the operating system, package, and runtime context. The wkhtmltopdf project documents dependencies on installed fonts, Fontconfig, and FreeType, and its builds can behave differently across distributions. Check the project’s downloads and platform notes for the target environment.

1. Capture the failing environment

Run these commands in the same container, service account, or serverless runtime that generates the PDF. A shell on your laptop is not a substitute for the production process environment.

wkhtmltopdf --version
uname -a
fc-list | head -40
fc-match sans-serif

If fc-list or fc-match is unavailable, Fontconfig utilities may not be installed even if the converter binary runs. Record the distribution and version, CPU architecture, installation package or binary, runtime user, relevant environment variables, and whether execution is in a container or serverless function. The project asks bug reports to include the version, operating system, and a detailed reproducer.

Create a minimal HTML file that reproduces the affected family and characters. Keep the sample small enough to distinguish font resolution from unrelated layout or JavaScript behavior:

cat > /tmp/font-check.html <<'HTML'
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <style>
    body { font-family: "Example Sans", sans-serif; }
    @font-face {
      font-family: "Example Sans";
      src: url("https://example.com/fonts/example-sans.woff2") format("woff2");
      font-weight: 400;
      font-style: normal;
    }
  </style>
</head>
<body>
  Latin: A quick brown fox. Affected script: replace this with failing text.
</body>
</html>
HTML
wkhtmltopdf --encoding utf-8 /tmp/font-check.html /tmp/font-check.pdf

Replace the example font URL and sample text with the real ones. To isolate system-font behavior from remote web-font loading, temporarily remove the @font-face rule and request a known installed family.

2. Distinguish bad encoding from missing glyphs

Look at the failure pattern:

  • Garbage characters, replacement diamonds, or question marks: investigate the HTML bytes, declared charset, HTTP response charset, and input encoding.
  • Boxes, blank spaces, or a visibly different fallback for one script: check glyph coverage and font-family resolution.
  • Every font looks different from another operating system: compare installed fonts, the converter build, and platform dependencies.

The --encoding option sets the default text encoding for input. It is useful when the document does not specify its encoding correctly, but it does not supply glyphs. A historical project issue about Chinese characters records an individual report that installing a Chinese font package fixed the missing characters after UTF-8 settings had not helped. That is evidence to check coverage, not a universal package recommendation. See the wkhtmltopdf command-line reference.

3. Verify the font is installed and visible

For system fonts, verify the font file is present in a directory visible to the process and that Fontconfig recognizes it. Then refresh the font cache if your distribution uses a cache and rerun fc-match for the requested family. Use the package manager and package name appropriate to the script and operating system; there is no single font package that covers every language.

# Examples for inspection; exact paths and package tools vary by distribution.
fc-list | grep -i 'Example Sans'
fc-match 'Example Sans'
find /usr/share/fonts -type f

When adding a custom font to an image or serverless bundle, include both the font file and any required Fontconfig configuration. Confirm readable file permissions for the actual service user. If Fontconfig returns a fallback family, the requested family may be misspelled, unavailable, or absent from the active configuration.

4. Check Fontconfig in containers and serverless jobs

Fontconfig configuration can differ between an interactive shell and a service process. An error such as Fontconfig error: Cannot load default config file is a reason to inspect the runtime’s configuration path, environment, mounted or bundled files, and permissions. A historical CentOS report describes this error outside an interactive shell despite installed dependencies; it does not establish a general fix.

The project’s AWS Lambda example bundles the runtime files and sets FONTCONFIG_PATH=/opt/fonts. That value applies to the described bundle layout only. Use the path where your configuration is actually packaged, and make sure the font files and libraries are present too.

# Example only when the Lambda layer places Fontconfig files under /opt/fonts.
export FONTCONFIG_PATH=/opt/fonts
export LD_LIBRARY_PATH=/opt/lib
/opt/bin/wkhtmltopdf /tmp/font-check.html /tmp/font-check.pdf

For a different container or function platform, inspect its filesystem and environment rather than copying these paths unchanged. If local works but the deployed job fails, compare the command, binary, environment variables, working directory, user, installed fonts, and mounted files.

5. Verify CSS web-font loading

A browser can load a font URL that wkhtmltopdf cannot. Check the renderer’s route, DNS, proxy, TLS trust, authentication, and relative URL base. A relative URL such as ../fonts/site.woff resolves from the document URL, which may differ from the path you expected when converting a local HTML file. Prefer an absolute asset URL or a deliberate local asset layout during diagnosis.

For local HTML that references local font files, wkhtmltopdf’s local-file access policy matters. The command reference documents --disable-local-file-access as the default and --allow <path> as a way to allow selected paths. Prefer allowing only the directory needed for the font assets. Do not enable broad local-file access unless the input is trusted and the access is required.

# Allow only the directory containing the local HTML and font assets.
wkhtmltopdf --allow /srv/report-assets /srv/report-assets/report.html /tmp/report.pdf

With remote fonts, confirm the exact response is a font file and that the URL is reachable from the machine running the process. Format-specific issue comments are inconsistent and version-dependent; converting every font to another format is not an established universal repair.

6. Match the binary and operating system

Record wkhtmltopdf --version and the package origin. The project’s download page lists the 0.12.6 stable series with a June 11, 2020 release date and explains why Linux builds are distribution-specific: system libraries and Fontconfig/FreeType configuration still matter. Its packages and support details may change, so check the current page for your target OS before installing or upgrading.

Do not assume that a binary described as static contains all system fonts or Fontconfig state. The project explains that static Qt linking does not remove runtime dependencies on system packages and installed fonts. A PDF generated on macOS or Windows can therefore differ from one created by a Linux service even with identical HTML and CSS.

7. Troubleshooting by symptom

Symptom Likely cause What to do
One language appears as boxes or missing symbols The chosen font lacks those glyphs, or the family resolves to a fallback without them. Check fc-match, install or bundle a font with the required script coverage, and retest the minimal sample.
Text is garbled across the document Incorrect input bytes or charset declaration. Save the document as UTF-8, declare <meta charset="utf-8">, inspect HTTP charset headers, and use --encoding utf-8 when a default is needed.
Cannot load default config file Fontconfig cannot find or read its configuration in this process context. Inspect FONTCONFIG_PATH, bundled config paths, permissions, service environment, and container mounts. Set a path only after confirming where the config lives.
Web font silently falls back Bad URL, relative path, inaccessible network or authenticated asset, local-file policy, or unsupported behavior in that build. Test the URL from the renderer host, use an absolute URL, inspect logs, and for local assets permit only the required directory.
Works locally but not in production Different binary, distribution, font inventory, runtime account, config, or network access. Compare version output and runtime details from both environments; reproduce under the production user and container.
Installed font does not appear in diagnostics Font is outside active directories, unreadable, or Fontconfig cache/config is stale. Check directory visibility and permissions, refresh the applicable cache, and rerun fc-list and fc-match.

8. A reliable production checklist

  1. Pin the wkhtmltopdf package or binary and the base operating-system image.
  2. Bundle or install the exact fonts required by the document, including coverage for every language you render.
  3. Include Fontconfig configuration and runtime libraries when packaging the converter into a container or function.
  4. Run a minimal font sample as the same user and with the same environment as the production conversion.
  5. Make web-font asset access explicit: stable absolute URLs or packaged local files with narrowly allowed paths.
  6. Keep a representative PDF in a release check so environment changes reveal font substitutions before rollout.
  7. Sanitize untrusted HTML and JavaScript. The wkhtmltopdf download page warns that untrusted input can expose the server to complete takeover.

9. Performance, reliability, and cost

Font diagnosis itself is inexpensive; the recurring operational cost is packaging and maintaining a consistent rendering environment. Bundling fonts makes rendering less dependent on host defaults, but adds font files and configuration to deployment artifacts. Remote fonts avoid bundling but add network, DNS, TLS, authentication, and availability dependencies to every conversion. Choose based on whether reproducibility or centralized asset updates matter more for your workflow.

Do not treat a successful exit code as proof that the intended font rendered. Keep logs, inspect generated PDFs for representative scripts, and test under the production runtime. The project’s platform notes describe meaningful differences among distribution builds, so pinning the binary and base image helps reduce unexpected variation. No benchmark or universal speed claim is established by the available evidence.

10. Or skip the browser setup

If your goal is to capture a webpage rather than produce a print-ready PDF through wkhtmltopdf, ScreenshotNeo is a website screenshot API and MCP server. Its API can return a screenshot or PDF from one GET request. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000.

For the full set of request options, see the ScreenshotNeo API documentation. This is a runnable cURL example saving a web screenshot:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Try it with 1,000 free screenshots a month, with no card.

FAQ

Does --encoding utf-8 fix missing font glyphs?

No. It helps wkhtmltopdf interpret text when the source encoding is unspecified or incorrect. The selected font still needs to contain the characters.

Should I convert WOFF or WOFF2 fonts to TTF?

Not as a blanket fix. Reports vary by version and environment. First prove that the asset is reachable and identify whether the runtime build can use it; test any format change with your actual document.

Why does a system font work on my laptop but not in Docker?

Containers have their own installed fonts, libraries, and Fontconfig configuration. Install or bundle the font and configuration in the image used for conversion.

What should I attach to a wkhtmltopdf bug report?

Include the exact version output, operating system and version, package or binary source, execution context, and a minimal HTML/CSS reproducer with the failing text and font declaration.

References