Skip to content

FreeSerif font not accessible to Jupyter Book in Docker container #3

Description

@mmcky

Summary

Docker container builds succeed, but Jupyter Book PDF builds fail with fontspec Error: The font "FreeSerif" cannot be found despite fonts being installed and verified. Standalone XeLaTeX compilation works, but latexmk subprocess (used by Jupyter Book) cannot access FreeSerif fonts.

Problem Details

Container: ghcr.io/quantecon/quantecon:latest
Base: Ubuntu 24.04, TeX Live 2023/Debian, XeTeX 3.141592653-2.6-0.999995
Environment: Python 3.13, jupyter-book==1.0.4post1

What Works ✅

  • Container builds successfully
  • fc-list | grep -i freeserif shows all FreeSerif font variants present
  • Standalone XeLaTeX: xelatex test.tex with \setmainfont{FreeSerif}SUCCESS
  • Jupyter Book HTML builds
  • Jupyter Book PDF builds when bypassing FreeSerif (using TeX default fonts)

What Fails ❌

  • Jupyter Book PDF builds with default configuration
  • Error occurs when polyglossia loads gloss-english.ldf and tries to use FreeSerif
  • latexmk subprocess (invoked by Jupyter Book) cannot find FreeSerif fonts

Debug Process

Attempts Made

  1. Added fonts-freefont-ttf package (Commit: c5fb92c)

    • Installed FreeSerif fonts via apt-get
    • Status: Fonts installed but still failed
  2. Added fontconfig + fc-cache (Commits: a0e2b2a, a5407e6)

    • Ran fc-cache -fv after apt-get and after conda setup
    • Verified fonts with fc-list | grep -i freeserif
    • Status: Cache built but still failed
  3. System-wide font cache (Commit: 71855c8)

    • Changed to fc-cache -f -s for system-wide cache
    • Hypothesis: User-specific cache not accessible to subprocess
    • Status: Still failed
  4. OSFONTDIR environment variable (Commit: 7b47508)

    • Set ENV OSFONTDIR=/usr/share/fonts
    • Explicitly tells XeTeX where to find system fonts
    • Status: Still failed
  5. Bypass FreeSerif fonts (Commit: fb6090e)

    • Added latex_elements: {fontpkg: ""} to _config.yml
    • Uses TeX Live's default Latin Modern fonts
    • Status: SUCCESS

Key Finding

Paradox: Same container, same fonts, different results:

  • Direct invocation: xelatex file.tex → FreeSerif works
  • Through latexmk: jb build . --builder pdflatex → FreeSerif fails

This suggests latexmk subprocess has restricted font access or different environment.

Why This Hasn't Come Up Before

  1. Production lecture repos use custom AMI runners, not Docker containers

    • AMI: quantecon-lecture-build-gpu-ubuntu2404-cuda13-cudann9
    • Instance: g4dn.2xlarge, direct runner (no container isolation)
    • Example: lecture-python.myst successful build shows FreeSerif working perfectly
  2. This container is new infrastructure being tested

    • First attempt to containerize lecture build process
    • Docker isolation reveals font accessibility issues not present on AMI
  3. Docker + latexmk + system fonts = known issue pattern

    • Common problem: subprocess environment differs from parent
    • Font cache location mismatch between build and runtime
    • Environment sanitization by latexmk

Evidence from Working Setup

Confirmed lecture-python.myst does use FreeSerif successfully:

TU/FreeSerif(0)/m/n/10 ... throughout PDF build

Same XeTeX version, same jupyter-book, same sphinx-jupyterbook-latex v1.0.0, but on AMI instead of Docker.

Proposed Solutions

Option A: Use TeX Default Fonts (Quick Fix)

Action: Configure lecture repos to use Latin Modern instead of FreeSerif

# _config.yml
sphinx:
  config:
    latex_elements:
      fontpkg: ""  # Use TeX defaults, not custom fonts

Pros:

  • Works reliably in containers
  • No font installation complexity
  • Immediate solution

Cons:

  • Changes PDF appearance
  • Inconsistent with AMI-based builds
  • Need to update all lecture repos

Option B: Match AMI Font Configuration

Action: Investigate and replicate AMI's font setup in container

  • SSH into AMI and examine: font packages, fontconfig settings, environment
  • Document differences between AMI and container environments
  • Replicate exact configuration

Pros:

  • Maintains consistency with current PDF output
  • Solves root cause

Cons:

  • Time-consuming investigation
  • May reveal complex interdependencies

Option C: Different Container Base

Action: Try alternative base images

  • nvidia/cuda:12.8.1-cudnn-devel-ubuntu24.04 (matches AMI base)
  • Official TeX Live Docker images
  • Ubuntu with full texlive-full package

Pros:

  • May just work out of the box
  • Closer to AMI environment

Cons:

  • Larger image sizes
  • May not solve underlying issue

Option D: Copy Fonts to TEXMF Tree

Action: Install fonts into TeX's font directory instead of system fonts

RUN mkdir -p /usr/local/share/texmf/fonts/truetype/freefont
RUN cp /usr/share/fonts/truetype/freefont/*.ttf \
       /usr/local/share/texmf/fonts/truetype/freefont/
RUN mktexlsr

Pros:

  • TeX will definitely find fonts in its own tree
  • Avoids fontconfig complexity

Cons:

  • Non-standard installation
  • May need additional font mapping files

Test Results Summary

Test Configuration Result
Standalone XeLaTeX Direct xelatex with FreeSerif ✅ SUCCESS
Jupyter Book HTML Default config ✅ SUCCESS
Jupyter Book PDF Default config (FreeSerif) ❌ FAILURE
Jupyter Book PDF fontpkg="" (no custom fonts) ✅ SUCCESS

Related Files

  • Container: containers/quantecon/Dockerfile
  • Test suite: containers/quantecon/tests/
  • Test workflow: .github/workflows/test-container.yml
  • Build workflow: .github/workflows/build-containers.yml

Next Steps

  1. Decide on solution approach based on priorities:

    • Speed vs consistency vs maintainability
    • Container adoption timeline
    • Acceptable differences from AMI builds
  2. For immediate container usage: Use Option A (default fonts)

  3. For long-term solution: Investigate Option B (match AMI) or Option D (TEXMF install)

Additional Context

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is wrong or broken

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions