Reading errors & debugging

LaTeX error messages read badly because they are not stack traces. The two stacked lines under ! Undefined control sequence are not an explanation of which command is wrong; they are a photograph of TeX's reading head at the instant it stopped — the upper line is what it had already read, the lower line what it had not, and the break between them is the scene of the accident. Once that clicks, the same single mechanism explains why the l.NN line number sometimes lies, whether to type h or x at the ? prompt, and why the .log file holds more than the terminal ever showed you. This page covers the anatomy of a TeX error, -file-line-error, the four -interaction modes, how to read the log, and how to bisect a document down to the culprit.

The anatomy of a TeX error: the ! line and the two stacked lines

The ! line tells you what happened; the two stacked lines starting at l.NN tell you where TeX stopped — and the culprit is almost always at the right-hand end of the upper line. TeX cuts the input line into what it has read and what it has not, stacks the halves, and marks the cut with indentation. In the example below the upper half ends with \textbnf, which is precisely the command that blew up the moment it was read; {bold} text. had not been touched yet, so it sits in the lower half. That cut is far more trustworthy than the line number: the number is where TeX noticed, the cut is where TeX was.

terminal
! Undefined control sequence.
l.3 This is \textbnf
                    {bold} text.
? 

Extra lines sometimes appear above l.NN; these are the error context. A line containing ->, such as \mynorm #1->\lVert, means the failure happened inside the expansion of that macro. <inserted text> is a token TeX supplied itself in order to recover, <to be read again> is a token it consumed and then pushed back, and <read *> means it is waiting for something typed at the terminal. When a line is too long for the terminal, its beginning is elided with ..., so a display like l.9 ...: $\frac{1}{2}$ and a stray \undefinedmacro means the real line starts further to the left.

Context lineWhat it marks
l.NNthe input line being read; the cut between the halves is where it stopped
\mac #1->it happened inside the expansion of \mac; the definition is elsewhere
<inserted text>a token TeX supplied itself to recover — often a $
<recently read>the token just consumed, which is usually the cause itself
<to be read again>a token consumed and pushed back; it will be read again next
<argument>it happened inside an argument — look at the argument, not the call
<read *>waiting for terminal input; a non-interactive mode aborts here at once

Why l.NN is sometimes exactly one line too far

An error raised by \usepackage is usually reported one line later than it happened, and the reason is the optional date argument that \usepackage allows at the end. Because \usepackage[opt]{pkg}[2021/02/14] is legal, TeX must peek past the closing brace to see whether a [ follows; that look-ahead skips spaces and line ends, so it has already pulled in the next line by the time the error fires. Measured on TeX Live 2024: with \usepackage[latin1]{inputenc} on line 3 the option clash is reported at l.4, and adding an explicit [2021/02/14] at the end of that same line moves the report to l.3. So if a package-related error points at a blank line or at \begin{document}, look one line up.

terminal
% \usepackage[latin1]{inputenc} sits on line 3 -- reported at line 4
./oc1.tex:4: LaTeX Error: Option clash for package inputenc.
l.4 \begin
          {document}

% same source, but the optional date argument is written out
% -- the look-ahead ends on line 3, and so does the report
./ocA.tex:3: LaTeX Error: Option clash for package inputenc.
l.3 \usepackage[latin1]{inputenc}[2021/02/14]

The same gap between “where TeX noticed” and “where the mistake is” opens up with an unclosed }, except that it can run to dozens of lines rather than one, with TeX finally giving up at the end of a paragraph or at \end{document}. The individual cases — dropped math mode, undefined commands, missing braces — each have their own page. The general rule is the only thing to carry away here: the more innocent the reported line looks, the further upstream the fault is.

-file-line-error: the format your editor can jump to

Pass -file-line-error and the leading ! is replaced by ./file.tex:3:, which puts the file name and the line number on one line so an editor or a CI log parser can jump straight there. The default format has a real gap: l.3 gives only a number, and the file name has to be inferred from an opening parenthesis such as (./chapters/intro.tex printed much further up. In a document split into chapters with \input, that inference is where the time goes. -file-line-error removes it, and the two stacked l.NN lines are still printed, so nothing is lost.

terminal
$ pdflatex main.tex
(./chapters/intro.tex
! Undefined control sequence.
l.2 Here is \nosuchcmd
                       in a chapter.

$ pdflatex -file-line-error main.tex
(./chapters/intro.tex
./chapters/intro.tex:2: Undefined control sequence.
l.2 Here is \nosuchcmd
                       in a chapter.

In many setups the format is already the default: latexmk turns it on internally, and front ends such as TeXworks or LaTeX Workshop for VS Code add it for you. When invoking the engine by hand, pass -file-line-error, or -no-file-line-error to switch it off explicitly. One useful side effect: when the error originates in a package, the path shown is that package's own file — a line reading /usr/local/texlive/…/foo.sty:120: means the complaint is coming from foo, not from anything you wrote.

The ? prompt: h, i, x, q, r, s and Return

There are nine possible replies at a ? prompt, and typing ? makes TeX print the list itself. This is the behaviour of the default errorstopmode, in which TeX is literally asking what to do. Three replies carry most of the traffic: Return (ignore this error and carry on), h (print TeX's own help paragraph for this message), and x (abandon the run at once, producing no PDF). When a long document is likely to hold more errors, the fastest route is to type r or s, let the run finish, and read the .log afterwards.

terminal
? ?
Type <return> to proceed, S to scroll future error messages,
R to run without stopping, Q to run quietly,
I to insert something, E to edit your file,
1 or ... or 9 to ignore the next 1 to 9 tokens of input,
H for help, X to quit.
?
ReplyWhat TeX does
Returnforget this error and carry on; typesetting continues and a PDF is still produced
hprint the help paragraph for this message; the .log has it already
iinsert text at that point — i\textbf fixes a typo for this run only
xabandon the run at once; it prints No pages of output. and writes no PDF
qprints OK, entering \batchmode and finishes the run in silence
rprints OK, entering \nonstopmode... and runs to the end without stopping
sprints OK, entering \scrollmode...; it does not stop, but will still read the terminal
eopen the editor named by the TEXEDIT environment variable at that line
1 … 9drop the next 1 to 9 tokens and continue; the line is redisplayed at the new cut

The four -interaction modes and when to use each

pdflatex --help lists four values — batchmode, nonstopmode, scrollmode, errorstopmode — and the default is errorstopmode. Use -interaction=nonstopmode when a script drives the run, and -interaction=batchmode when a CI job should not fill the terminal. Only two axes separate the four: whether it stops, and whether it writes to the terminal. The most misunderstood pair is scrollmode versus nonstopmode. Measured: a document that calls \typein really does read the answer from the terminal under scrollmode, and dies with ! Emergency stop. under nonstopmode. The dividing line is not errors but terminal input.

ModeStops? Writes to the terminal?
errorstopmodethe default; stops at every error with a ? prompt — right for hands-on work
scrollmodedoes not stop for errors but still reads the terminal; good for skimming a whole run
nonstopmodenever reads the terminal; if something asks, it ends with ! Emergency stop.
batchmodenonstopmode plus terminal output suppressed; the .log is still written in full

Saying that batchmode prints nothing is almost true. Running the same faulty document on TeX Live 2024 and measuring, the terminal receives 1212 bytes under nonstopmode and 144 bytes under batchmode — what survives is the pdfTeX banner and entering extended mode, both printed before the interaction mode takes hold. The .log, meanwhile, is 4144 bytes in both cases, byte for byte the same, and the PDF is produced either way. So batchmode is not discarding information; it is only keeping it off the terminal. The standard CI recipe follows from that: run in batch mode, decide pass or fail from the exit status covered in the next section, and archive the .log for the details. All four names are TeX primitives as well as command-line options, so writing \nonstopmode at the top of a file has the same effect.

-halt-on-error and the exit status

-halt-on-error abandons the run at the first error. Verified on TeX Live 2024: right after the first ! Undefined control sequence it prints ! ==> Fatal error occurred, no output PDF file produced! and quits, leaving no PDF. The same document under plain -interaction=nonstopmode reports all four errors and still writes a PDF, so the flag is what you want when a broken document must not look like a successful build. The exit status was measured too: 1 if there was any error at all, 0 if there was none. That does not depend on the mode — nonstopmode and batchmode behave alike — and warnings never change it. So a pdflatex && … chain in a Makefile or a CI job stops on errors only.

shell
# interactive: stop at the first error and look at it
pdflatex -file-line-error -halt-on-error document.tex

# CI: quiet terminal, full log on disk, exit status decides
pdflatex -interaction=batchmode -halt-on-error -file-line-error document.tex
echo $?      # 1 if any error occurred, 0 if none

Reading the .log: it holds more than the terminal ever showed

The .log contains the help paragraph the terminal never printed, so when a message makes no sense there is no need to reproduce it and type h — just open the log. Measured on one run: 938 bytes reached the terminal while the .log held 3199, and most of the difference is that help text. The effect is largest for an option clash, where the terminal shows only ! LaTeX Error: Option clash for package inputenc. while the log spells out which options the package was first loaded with and which ones have just been requested. Those four lines are the difference between guessing and knowing.

log
% only the first line of this reaches the terminal
./oc1.tex:4: LaTeX Error: Option clash for package inputenc.
...
The package inputenc has already been loaded with options:
  [utf8]
There has now been an attempt to load it with options
  [latin1]
Adding the global options:
  utf8,latin1
to your \documentclass declaration may fix this.

Learning the shape of the whole log pays off too. The first line names the engine, its version and the run's date and time; the next shows the invocation as **document.tex; after that everything is nested parentheses — ( opens a file and ) closes it, so the nesting is the answer to “which file pulled this package in”. [1], [2] mark shipped-out pages, and the tail is the memory tally after Here is how much of TeX's memory you used: followed by Output written on document.pdf (1 page, 12817 bytes).. If you would rather not face all that, pipe the run through texfot, shipped with TeX Live, which trims the output down to errors, warnings and the final summary line.

terminal
$ texfot pdflatex -interaction=nonstopmode two.tex
texfot: invoking: pdflatex -interaction=nonstopmode two.tex
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024)
! Undefined control sequence.
l.3 First \foo
! Missing $ inserted.
<inserted text>
l.4 Second \bar
Output written on two.pdf (1 page, 23091 bytes).

\listfiles and the *File List* block: counting what actually loaded

Add a single \listfiles anywhere in the preamble and the .log gains a *File List* table at the end, naming every file that was loaded with its date, version and one-line description. Counted on TeX Live 2024: a bare article loads 3 files (article.cls, size10.clo, l3backend-pdftex.def). Adding one line of hyperref takes that to 33 — hyperref alone drags in 30 more. tikz gives 34. This is the first move whenever a package you never asked for turns out to be involved in a clash. It is also what to paste when posting a question or filing a bug: the table makes a mismatch between two installations obvious at a glance.

log
% \listfiles goes anywhere in the preamble; this lands at the end of the .log
 *File List*
 article.cls    2023/05/17 v1.4n Standard LaTeX document class
  size10.clo    2023/05/17 v1.4n Standard LaTeX file (size option)
 amsmath.sty    2023/05/13 v2.17o AMS math features
hyperref.sty    2024-01-20 v7.01h Hypertext links for LaTeX
   iftex.sty    2022/02/03 v1.0f TeX engine tests
 ***********

For a finer-grained view, add -recorder. Every file opened during the run is written to a .fls file as an INPUT line — a document whose only package is tikz produces 140 of them. Where \listfiles answers “which packages were loaded”, .fls answers “which files were touched”, right down to font .tfm files and configuration files. The first is what you want when chasing a package clash; the second when chasing where kpathsea actually looked.

\show, \showthe, \typeout: printing what TeX believes

\show\foo prints the definition of \foo, and \showthe\textwidth prints the value of a length or counter. The output lands in the .log as > \LaTeX=macro: or > 345.0pt. — the leading > is the marker, and 345.0pt happens to be article's default \textwidth. When you cannot remember how a command is currently defined, \show beats guessing, and it usually settles whether the class or a package did the redefining. To emit your own messages there are \typeout{…} and \message{…}; measured, \typeout puts its text on a line of its own while \message appends to the current line. The first is easier to read for printf-style debugging, the second is handy for marking a spot next to a page number.

latex
\show\LaTeX            % > \LaTeX=macro:  ... (definition follows)
\showthe\textwidth     % > 345.0pt.       (article default)
\typeout{reached the theorem}   % own line in log and terminal
\message{mark}                  % appended to the current line
\tracingall            % dump every step to the log -- extremely verbose

The last resort is \tracingall, which writes every step TeX takes — macro expansions, mode changes, attempted line breaks — into the log. It can reach tens of megabytes on a document of a few pages, so as a rule turn it on immediately before the trouble and back off with \tracingnone immediately after, or pair it with the trace package, which tidies the output into something readable. \tracingall answers “in what order did this happen”, not “which macro is at fault” — and once the order is clear, a single \show usually settles the rest.

Bisecting a document: move \end{document} up

When the message alone is not enough, halving the document is the shortest route: write an extra \end{document} partway through the body and everything after it is ignored. Verified on TeX Live 2024 — whatever follows \end{document}, including a broken command, is never read. You therefore do not even need to delete the original one; just slide the added line up and down to close in from both sides. Ten moves narrow a thousand-line document to a single line. If the preamble is the suspect, comment out half the \usepackage lines with % at a time, and if chapters are split with \include, use \includeonly{chapter3} instead.

document.tex
\begin{document}
\input{chapters/intro}
\input{chapters/method}

\end{document}   % <- added: bisect here, everything below is ignored

\input{chapters/results}
\input{chapters/discussion}
\end{document}

Once you are down to half, keep cutting all the way to the smallest thing that still fails. Remove \usepackage lines one at a time, throw away body text a paragraph at a time, replace figures with example-image (shipped with graphicx) and long passages with lipsum, and what is left is usually a dozen lines or so. At that size the cause is normally obvious; and if it still is not, those dozen lines are exactly what you paste into a question. The cutting is itself the diagnosis — the etiquette of asking well, and where to ask, is covered on the community page.