Pitfalls for MathJax in HUGO

The real fix: enable Goldmark's passthrough extension

Rules 1-5 below are all workarounds for one underlying gap: by default, Hugo's Goldmark renderer has no concept that text between \(...\) / \[...\] is math that should be left alone. It runs its normal markdown inline parser over that text first - catching subscript underscores next to ), }, ( as accidental emphasis delimiters - and only hands the (already damaged) result to MathJax.

Hugo ships a built-in fix for exactly this: the passthrough extension. Add this to your site config (config.toml / hugo.toml):

[markup]
  [markup.goldmark]
    [markup.goldmark.extensions]
      [markup.goldmark.extensions.passthrough]
        enable = true
        [markup.goldmark.extensions.passthrough.delimiters]
          block = [['\[', '\]'], ['$$', '$$']]
          inline = [['\(', '\)']]

Use the same delimiters you already load in math.html's MathJax config. Once this is enabled and the site is rebuilt, Goldmark leaves everything between the delimiters completely untouched, and most of the workarounds below become unnecessary. Keep rules 1-5 as a fallback/diagnostic checklist for any content still rendered without passthrough enabled (e.g. older posts, other themes, or if passthrough is ever disabled).

Critical: your content files must use the exact same delimiter characters as the config, or passthrough silently does nothing. Before passthrough existed, it was common to write \\(...\\) / \\[...\\] (double backslash) in markdown, because Goldmark's normal escape handling collapses \\ into a single \, which happened to produce the right delimiter for MathJax by accident. Once passthrough is enabled with the config above (single backslash: '\[', '\)', etc.), that double-backslash source text no longer matches - the parser never recognizes the delimiter, so it falls straight through to Goldmark's ordinary markdown parser and you get the exact same corruption as if passthrough were never enabled. If you enable passthrough and equations are still breaking, first check whether your markdown source uses \\(/\\[ (double) instead of \(/\[ (single) - a site-wide find-and-replace to single backslash is required for passthrough to actually take effect.

Introduction

Lessons learned from debugging math rendering on my Hugo site (MathJax 3 loaded via math: true flag in the markdown files and {{ partial "math.html" . }} before the </head> tag in themes/<your-theme>/layouts/_default/baseof.html).

These are not MathJax bugs - they are Goldmark (Hugo's Markdown renderer) mangling LaTeX before MathJax ever sees it. Every fix below works around Goldmark's parsing, not MathJax's.

1. Display math must be on a single line

Broken:

\\[
\sum_{k=1}^{n} f(k) = \int_1^n f(x)\,dx
+ \frac{f(1)+f(n)}{2}
+ R_p
\\]

Goldmark can break multi-line \\[...\\] blocks - especially if a line inside looks like a list item (starts with +, -, *, or a number followed by .). The leading + on its own line was read as a Markdown bullet point.

Fix: put the entire equation on one line.

\\[
\sum_{k=1}^{n} f(k) = \int_1^n f(x)\,dx + \frac{f(1)+f(n)}{2} + R_p
\\]

2. Never use literal square brackets [ ] inside an equation

Broken:

\\[ t_n = 1 + \frac{n-1}{2}[8 + (n-2) \cdot 2] \\]

Goldmark's Markdown-link parser actively scans for [...](...) patterns. A bracket followed shortly by a parenthesis - even deep inside what is obviously a LaTeX expression - can get misread as a link, silently corrupting or dropping the surrounding math. This happened even when escaped with \bigl[ / \bigr], because the characters [ and ] are still there for the Markdown tokenizer to find.

Fix: use parentheses-based delimiters instead - \Bigl( ... \Bigr), \left( ... \right), or plain (...). Never rely on \[-escaping inside inline contexts to protect square brackets; replace the bracket entirely.

\\[ t_n = 1 + \frac{n-1}{2}\Bigl(8 + (n-2) \cdot 2\Bigr) \\]

3. Avoid \text{...} for short labels inside superscripts/subscripts; prefer \mathrm{...}

Symptom: one equation with S_{n-1}^{\text{arith}} failed to render while a nearly identical one with S_{n-1}^{\text{geom}} worked fine. The actual cause turned out to be rule #2 (a bracket later in the same equation) - but \text{} nested inside {...}^{...} is itself fragile in some Goldmark + MathJax combinations and is worth avoiding as a precaution.

Fix: use \mathrm{...} for upright text labels in sub/superscripts when no italic text-mode features (spacing, accents) are needed.

S_{n-1}^{\mathrm{arith}}      instead of      S_{n-1}^{\text{arith}}

4. Don't mix \leq, \sum, \int etc. in a long inline \(...\) expression

Broken:

\\(\int_0^n f \leq \sum_{k=1}^n f(k)\\)

Long inline expressions with multiple big operators are more likely to trip Goldmark's inline-parsing edge cases (especially around escaping of \ sequences) than the same expression in display mode.

Fix: promote anything with more than one "big" operator (\sum, \int, \prod, relations like \leq/\geq combined with operators) to a display block.

\\[ \int_0^n f(x)\,dx \leq \sum_{k=1}^{n} f(k) \\]

5. Dense inline math inside a prose sentence gets corrupted, even on one line

Broken:

Section 4 below has the same two properties: the boxed identity
\\(t_n^{(\ell)} = t_1^{(\ell)} + S_{n-1}^{(\ell+1)}\\) builds each level from a seed
term plus an expansion of the level beneath it...

This looked safe by rules 1-4 above: the whole \\(...\\) span was on a single line, had no literal [/], used no \text{}, and had no \leq/\sum/\int. It still rendered broken - characters were silently dropped in an inconsistent pattern (t_n became tn, S_{n-1} became S{n-1}, some ( characters vanished while others survived). The common thread with rule 4: this expression had three separate ^{...} / _{...} groups packed into one inline span, embedded in an ordinary sentence Goldmark was also parsing for regular markdown syntax at the same time.

Fix: once an inline expression has more than about two sub/superscript groups, stop trying to keep it inline - promote it to its own display block (\\[...\\]) on its own line, and let the surrounding sentence refer to it rather than contain it.

Section 4 below has the same two properties: its boxed identity

\\[
t_n^{(\ell)} = t_1^{(\ell)} + S_{n-1}^{(\ell+1)}
\\]

builds each level from a seed term plus an expansion of the level beneath it...
  1. Isolate the single equation that fails - don't try to fix the whole file at once.
  2. Check it against rules 1-4 above, in that order (multi-line → brackets → text-mode labels → inline complexity).
  3. Make ONE change at a time and re-test, since multiple suspect patterns can co-occur in the same equation (as happened with Example 1 above: it had both \text{} and a bracket, and the bracket was the real cause, not the text command).
  4. Don't trust "this one rendered, that one didn't" as proof of which syntax is at fault - compare character-by-character for ALL differences, not just the obvious one.

Quick checklist before publishing any new equation

Previous:
Symmetries in Arithmetic and Geometric Series
Next:
Median Formula for Continuous Grouped Data