Fix: Unicode and CJK characters break nbconvert PDF export
If jupyter nbconvert --to pdf drops your Chinese, Japanese, or Korean text, renders it as empty boxes (tofu), or crashes outright with a LaTeX error, the cause is the LaTeX engine: nbconvert's default PDF path uses pdflatex, which does not handle most non-Latin Unicode. The fix is to render with XeLaTeX plus a CJK font and the xeCJK package. Alternatively, skip the LaTeX toolchain entirely, an HTML-based or browser converter renders Unicode using ordinary system fonts, with no font packages to configure. PDFMoka's ipynb to PDF converter takes that second route: it renders in your browser using your system's fonts, so CJK and other Unicode work without any LaTeX setup. Here is the full picture.
Why pdflatex chokes on Unicode
nbconvert builds a PDF by generating LaTeX and compiling it. The default compiler, pdflatex, has poor Unicode coverage: many UTF-8 characters (CJK scripts, emoji, some accented and combined characters) are simply unrecognizable to it, so they either get silently dropped or trigger a compilation error that aborts the whole export. This is not an nbconvert bug; it is a limitation of the pdflatex engine.
Two symptom patterns, same root cause:
- Characters missing or shown as boxes (tofu). The compile succeeds but the glyphs are gone, because pdflatex (or the default font) has no glyph for them.
- Export crashes with a LaTeX error. A character pdflatex cannot process at all halts compilation.
Fix 1: use XeLaTeX with a CJK font
XeLaTeX natively supports Unicode and reads UTF-8 by default, and it can use fonts installed on your operating system. This is the standard, reliable fix for CJK notebooks. It requires a custom nbconvert LaTeX template that loads fontspec and xeCJK and names a CJK font you have installed (for example Noto Sans CJK). The widely used template pattern extends the default template's header to add:
\usepackage{fontspec}
\usepackage{xeCJK}
\setmainfont{Latin Modern Roman}
\setCJKmainfont{Noto Sans CJK SC} % or another installed CJK font
and then converts with that template:
jupyter nbconvert notebook.ipynb --to pdf --template your_cjk_template
Prerequisites: XeLaTeX must be installed (part of texlive-xetex), and a CJK font must be available (for Chinese, texlive-lang-chinese or a system font like Noto Sans CJK).
verify against current docs: nbconvert's template system has changed across versions (older
.tplxvs newer.tex.j2+conf.json); the exact template syntax depends on your nbconvert version. This has been a long-standing pain point (nbconvert has an open discussion about shipping an official CJK template), so confirm the current template format and the correct\setCJKmainfontname for a font you actually have installed before relying on it. There are also community templates (search for jupyter CJK xelatex) that package this for you, verify they match your version.
For a broader look at Unicode/CJK in the closely related Markdown-to-PDF case (same pdflatex-vs-xelatex issue in Pandoc), see Markdown to PDF: Pandoc vs online.
Fix 2: avoid LaTeX entirely (render with system fonts)
The Unicode problem is fundamentally a LaTeX-toolchain problem. If you render the notebook as HTML and print that to PDF, or use a browser-based converter, the text is drawn with ordinary system fonts that already contain CJK glyphs, and there is nothing to configure.
- Browser converter, no setup: PDFMoka's ipynb to PDF tool renders in your browser using your system fonts, so CJK, accented characters, and most Unicode work out of the box, and the notebook is never uploaded, which matters for documents in languages tied to sensitive or internal content. (One honest caveat: it can only display glyphs your device actually has a font for; on a system with CJK fonts installed, which is normal for CJK users, this is a non-issue.)
- nbconvert webpdf:
jupyter nbconvert --to webpdf notebook.ipynbrenders through headless Chromium instead of LaTeX, which also sidesteps the pdflatex Unicode limits. See convert a notebook to PDF without LaTeX for setup.
For CJK users specifically, the LaTeX-free route is usually the path of least resistance: no template hacking, no font-package debugging, the text just renders.
Which fix?
- You need the LaTeX-typeset look and are willing to configure a template + font: Fix 1 (XeLaTeX + xeCJK).
- You just want the characters to render, minimal fuss: Fix 2, a browser converter or nbconvert webpdf, using system fonts.
If the error you are actually seeing is xelatex not found on PATH (rather than missing glyphs), that is a separate install problem, see the nbconvert xelatex fix.
References
- jupyter/nbconvert issue #281 (pdflatex fails on emoji/utf8; XeLaTeX supports Unicode): https://github.com/jupyter/nbconvert/issues/281
- jupyter/nbconvert issue #2253 (CJK characters render as tofu; xeCJK template pattern): https://github.com/jupyter/nbconvert/issues/2253