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
-
Added fonts-freefont-ttf package (Commit: c5fb92c)
- Installed FreeSerif fonts via apt-get
- Status: Fonts installed but still failed
-
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
-
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
-
OSFONTDIR environment variable (Commit: 7b47508)
- Set
ENV OSFONTDIR=/usr/share/fonts
- Explicitly tells XeTeX where to find system fonts
- Status: Still failed
-
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
-
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
-
This container is new infrastructure being tested
- First attempt to containerize lecture build process
- Docker isolation reveals font accessibility issues not present on AMI
-
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
-
Decide on solution approach based on priorities:
- Speed vs consistency vs maintainability
- Container adoption timeline
- Acceptable differences from AMI builds
-
For immediate container usage: Use Option A (default fonts)
-
For long-term solution: Investigate Option B (match AMI) or Option D (TEXMF install)
Additional Context
Summary
Docker container builds succeed, but Jupyter Book PDF builds fail with
fontspec Error: The font "FreeSerif" cannot be founddespite 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:latestBase: 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 ✅
fc-list | grep -i freeserifshows all FreeSerif font variants presentxelatex test.texwith\setmainfont{FreeSerif}→ SUCCESSWhat Fails ❌
gloss-english.ldfand tries to use FreeSerifDebug Process
Attempts Made
Added fonts-freefont-ttf package (Commit: c5fb92c)
Added fontconfig + fc-cache (Commits: a0e2b2a, a5407e6)
fc-cache -fvafter apt-get and after conda setupfc-list | grep -i freeserifSystem-wide font cache (Commit: 71855c8)
fc-cache -f -sfor system-wide cacheOSFONTDIR environment variable (Commit: 7b47508)
ENV OSFONTDIR=/usr/share/fontsBypass FreeSerif fonts (Commit: fb6090e)
latex_elements: {fontpkg: ""}to_config.ymlKey Finding
Paradox: Same container, same fonts, different results:
xelatex file.tex→ FreeSerif worksjb build . --builder pdflatex→ FreeSerif failsThis suggests latexmk subprocess has restricted font access or different environment.
Why This Hasn't Come Up Before
Production lecture repos use custom AMI runners, not Docker containers
quantecon-lecture-build-gpu-ubuntu2404-cuda13-cudann9This container is new infrastructure being tested
Docker + latexmk + system fonts = known issue pattern
Evidence from Working Setup
Confirmed lecture-python.myst does use FreeSerif successfully:
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
Pros:
Cons:
Option B: Match AMI Font Configuration
Action: Investigate and replicate AMI's font setup in container
Pros:
Cons:
Option C: Different Container Base
Action: Try alternative base images
nvidia/cuda:12.8.1-cudnn-devel-ubuntu24.04(matches AMI base)Pros:
Cons:
Option D: Copy Fonts to TEXMF Tree
Action: Install fonts into TeX's font directory instead of system fonts
Pros:
Cons:
Test Results Summary
Related Files
containers/quantecon/Dockerfilecontainers/quantecon/tests/.github/workflows/test-container.yml.github/workflows/build-containers.ymlNext Steps
Decide on solution approach based on priorities:
For immediate container usage: Use Option A (default fonts)
For long-term solution: Investigate Option B (match AMI) or Option D (TEXMF install)
Additional Context
/tmp/font-test-analysis.txt