Missing $ inserted

! Missing $ inserted is the most common error in LaTeX, and the help text printed underneath it ends with the words Proceed, with fingers crossed. That wording is Donald Knuth’s, written into TeX itself in the 1980s, and it still appears on somebody’s screen every day. The message means exactly one thing: something that is only legal inside mathematics turned up in ordinary text. The culprit is usually an underscore _ you meant literally, a superscript ^, a stray \alpha, or a $ far earlier that never got closed. This page covers how to read the message, why the line number it reports is often later than the mistake, and what to write instead in the three places where the answer differs: plain text, \verb, and \url.

What ! Missing $ inserted is actually complaining about

It means that a token which only exists in math mode arrived while TeX was setting ordinary horizontal text — nothing more. TeX guesses you forgot to open math, silently inserts a $, and carries on. So the fix is a single sentence: if you meant mathematics, wrap it ($x_1$); if you meant the character itself, escape it (\_). One level down, the mechanism is category codes. TeX assigns every input character a number: _ is catcode 8 (subscript), ^ is 7 (superscript), $ is 3 (math shift). Catcodes 7 and 8 are legal only inside mathematics. \alpha and \frac fail for the same reason — internally they ask for math-class characters.

latex
% "$" is not sacred: it is just the character whose catcode is 3.
% Give catcode 3 to "!" and it opens and closes math exactly like $.
\catcode`\!=3
Then !x_1! typesets as math.   % compiles with zero errors

The snippet above looks like a joke, but it compiles without a single error under TeX Live 2024. $ is not sacred; it is merely the character whose catcode happens to be 3. Once that clicks, the error stops being mysterious: it is a mix-up about what role a character plays. It also follows that _ and ^ are not the only special characters that misbehave in text — but a different character gives a different error, so use the table below to place your symptom. This is a common misconception: writing & in ordinary text does not produce ! Missing $ inserted.

CharacterCatcodeWhat happens if you write it in text
_8! Missing $ inserted. For a literal underscore write \_
^7! Missing $ inserted. The literal sign is \textasciicircum
$3Opens/closes math. One of a pair leaves math open to the paragraph end
&4A different error: ! Misplaced alignment tab character &. Literal sign is \&
%14No error at all. It eats the rest of the line — including a closing $
#6! You can’t use ‘macro parameter character #’ in horizontal mode
~13No error; it becomes a non-breaking space (literal sign: \textasciitilde)

How to read <inserted text> and the l.3 line

The $ shown under <inserted text> is something TeX added by itself — it is not in your file. The l.3 line, by contrast, is the scene of the crime: TeX prints the offending line broken into two halves, and the break is exactly how far it had read. Below is the real output from running pdfLaTeX (TeX Live 2024) on a four-line file whose body is just The value x_1 is here. Notice that the break falls immediately after x_: TeX stopped the instant it read the underscore. This two-part display is the single most useful thing in a TeX error report, because it pinpoints the position within a long line.

log
! Missing $ inserted.
<inserted text>
                $
l.3 The value x_
                1 is here.
I've inserted a begin-math/end-math symbol since I think
you left one out. Proceed, with fingers crossed.

The identical message, word for word, comes out of plain TeX as well. It is therefore not a LaTeX message but a message from the TeX engine itself, and it appears even with no \usepackage line anywhere in the file. That is why, when hunting the cause, you should suspect the characters you typed before you suspect a package. The closing sentence of the help text, Proceed, with fingers crossed, has been essentially unchanged since TeX was frozen in 1990.

Why the reported line number is later than your mistake

TeX reports the line where it noticed, not the line where you erred. For something illegal the instant it is read, like _, the two coincide. But for the kind of mistake that leaves math open — a $ that never gets closed — TeX only notices when the paragraph ends, that is, at the next blank line. Because a formula may not span a paragraph break, reaching a blank line is the first moment TeX can conclude that math is still open. In the file below the mistake is on line 3, but the error is reported on line 4, the blank line.

document.tex
\documentclass{article}
\begin{document}
The rate is $x% of the total$ per year.

Next paragraph.
\end{document}
log
! Missing $ inserted.
<inserted text>
                $
l.4

I've inserted a begin-math/end-math symbol since I think
you left one out. Proceed, with fingers crossed.

The trap is the % on line 3. An unescaped percent sign comments out the rest of that line — including the closing $ — so math stays open into the next line. Nothing is printed to the right of l.4 because line 4 is the blank line. When the error line is blank, read it as “math has been open since somewhere earlier.” In practice the fastest move is to go to the paragraph immediately before the reported line and count the $ signs in it. Editors match braces but not $, so this one is on you. By the same mechanism, a line where you typed 50% instead of 50\% will produce a baffling error several lines later.

Printing a literal underscore: \_, \textunderscore, and _ inside \verb

If all you want is a filename like data_set.csv, the answer is data\_set.csv. But the relationship between \_ and \textunderscore is worth knowing. In the kernel file latex.ltx, \_ is defined as “\nfss@text{\textunderscore} in math mode, otherwise \textunderscore” — they are the same thing. In text the two are exactly equivalent; \_ is just the short form that also survives math mode. What matters more comes next: under the default OT1 encoding the underscore is drawn as a rule, not set as a character. The kernel definition is \leavevmode \kern.06em\vbox{\hrule\@width.3em} — a horizontal rule 0.3 em wide. As a result you cannot copy the underscore out of the PDF, and PDF search will not find it. Add \usepackage[T1]{fontenc} and t1enc.def’s \DeclareTextSymbol{\textunderscore}{T1}{95} takes over, giving a real glyph that copies and searches. Run the same document through pdftotext and the OT1 version yields data set while the T1 version yields data_set.

What you writeResultWhen to use it
\__the standard form; works in text and in math
\textunderscore_what \_ expands to; no difference in text
\verb|a_b|a_bno escaping; writing \_ inside prints a backslash too
underscore_a package; load it and a bare _ becomes safe in text
\textasciicircum^a literal caret, not a superscript
latex
% math, when you mean math
The value $x_1$ and $\alpha$ are positive, and $x^2 \ge 0$.

% characters, when you mean characters
Open data\_set.csv, then press \textasciicircum{}C to stop.

% verbatim, when the string is code
Run \verb|make data_set^2| in the shell.

Inside \url and siunitx the answer is reversed

Do not escape _ inside \url{...}. \url{https://example.com/a_b} compiles correctly as it stands, whereas \url{a\_b} prints a\_b, backslash and all. The reason is that the url package rewrites category codes before reading its argument, turning _ and its fellow specials back into ordinary characters. The same spirit applies to siunitx: \num and \qty open math internally, so \qty{2.5}{\micro\metre} can be written straight into running text. In other words, what you should type depends on whose argument you are standing in. The rule of thumb is simple: if the command treats its contents verbatim, use the bare character; otherwise escape it. \verb, \url and listings\lstinline are the first kind; \section, \caption and \footnote are the second.

latex
\usepackage{url}       % or hyperref, which loads url
\usepackage{siunitx}
...
\url{https://example.com/a_b}    % right: bare underscore
\url{https://example.com/a\_b}   % wrong: prints the backslash
\qty{2.5}{\micro\metre}          % siunitx opens math for you

A blank line inside \[ … \], and ! Display math should end with $$

One blank line inside display math produces three separate errors. You split a formula across two lines to make it readable, and the document breaks. Put a blank line between \[ E = mc^2 and F = ma and TeX Live 2024 emits, in order, ! Missing $ inserted, ! Display math should end with $$, and ! LaTeX Error: Bad math environment delimiter. All three descend from the single rule that a formula may not cross a paragraph break. To split a formula, use an align environment or \\, never a blank line; to run prose between two lines of a display, use amsmath’s \intertext. Note that ! Display math should end with $$ also appears when the opening and closing dollar counts disagree, as in $$ … $. In LaTeX the idiom is \[ … \] rather than $$, because $$ ignores the display spacing parameters such as \abovedisplayskip.

log
! Missing $ inserted.
<inserted text>
                $
l.5

! Display math should end with $$.
<to be read again>
                   \tex_par:D
l.5

! LaTeX Error: Bad math environment delimiter.
l.7 \]

When one mistake turns into five errors

When errors come in a flood, fix only the first one. The rest are almost always collateral damage from the $ TeX inserted. Compile a file whose body is just \frac{1}{2} in ordinary text and you get a chain of three: ! Missing $ inserted (at \frac), ! Extra }, or forgotten $. (from the closing brace of the \over inside \frac’s definition), and ! Missing $ inserted again at \end{document}. After the first error TeX carries on still in math mode, so all the following text is interpreted as mathematics — odd gaps appear inside words, punctuation spacing breaks, and further errors rain down. The procedure is therefore fixed: correct the first error and compile again. Reading the second and later messages before that is wasted effort.

  • Jump to the l.N given in the message and read that line up to the break; the character just after the break is the culprit.
  • If the break lands on a blank line, count the $ signs in the paragraph before it — an odd count means one is unclosed.
  • Scan the same line for a % you did not intend as a comment, swallowing the closing $.
  • If you meant mathematics write $ … $; if you meant characters write \_, \%, \&, \#, \textasciicircum{}.
  • To show code or identifiers verbatim, use \verb or listings and stop reasoning about escapes one character at a time.
  • After a fix, recompile before reading the next error.