A ?? appears where a number should be, and the log says LaTeX Warning: There were undefined references. It is the first piece of apparent absurdity every LaTeX user meets. The reason a reference comes out as ?? is that LaTeX takes its numbers from the .aux file left behind by the previous run. So ?? and the classic question “why do I have to compile twice?” are two sides of one coin. This page covers that two-pass machinery, how to tell Label(s) may have changed, multiply defined and Citation ... undefined apart, the correct run order once BibTeX or Biber is in the loop, and — the nastiest trap of all — the placement of \label that prints the wrong number without emitting a single warning.
Why do I have to compile twice?
Because LaTeX does not know the number of anything that lies ahead until it has read the document from top to bottom once. Write “see Chapter 7” on page 3 and, at that moment, what page Chapter 7 will land on is undecided. So LaTeX writes every \label it finds during the first run into an .aux file, reads that file back at the start of the second run, and only then fills the numbers in. The first pass is therefore guaranteed to give ?? — that is the design, not a bug. And the problem is circular: when a reference changes from ?? (two characters) to 12 (two characters, but different ones), the line breaking changes; when the line breaking changes, page numbers change; when page numbers change, \pageref values change. LaTeX resolves the circle by iterating until it settles, and the message that reports whether it has settled is LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right. Run again until that sentence is gone — that is the whole discipline.
Looking inside an .aux file once makes the whole mechanism click. Below is an excerpt after two runs of a document containing \section{The section}\label{sec:s} — first plain LaTeX, then the same with hyperref loaded. \newlabel takes five arguments, of which the first is the number and the second is the page. \ref simply extracts the first; \pageref extracts the second. With hyperref, the third holds the heading text and the fourth the anchor name. \nameref{sec:s} can print “The section” because of that third field, and \ref becomes a clickable link because of the fourth. This also explains why deleting a damaged .aux and rebuilding it is always safe: everything in it is derived, and is regenerated from scratch on every run.
% plain LaTeX: {number}{page}{}{}{}
\newlabel{sec:s}{{1}{1}{}{}{}}
% with hyperref: {number}{page}{title}{anchor}{}
\newlabel{sec:s}{{1}{1}{The section}{section.1}{}}Counting the runs by hand is a waste of a human, so a tool grew up to make the decision for you: latexmk. It reads the log and keeps going until Rerun to get cross-references right is gone, slotting in BibTeX or index processing along the way when needed. Its provenance is rather charming. The header of the latexmk shipped in TeX Live 2024 records that the original was a 1992 script called go, written by David J. Musliner at the University of Michigan. Evan McLean then reworked it, John Collins took over in 1998, and the version bundled today is 4.83, dated January 2024. A plain irritation — “how many times am I supposed to compile this?” — has sustained a tool for more than thirty years.
Telling the warnings apart: “not yet” versus “genuinely missing”
The test is simple: run it twice and see whether the same warning survives. A warning that appears only on the first pass is normal behaviour; a warning that is still there on the second is a real problem. Compile a document containing one \ref{nope} (a label that does not exist) and one \ref{sec:real} (a label that does), and the first pass reports both as undefined, closing with There were undefined references. and Label(s) may have changed. Rerun to get cross-references right. On the second pass sec:real is gone, only nope remains, and Label(s) may have changed has disappeared. Looking at the kernel file latex.ltx, there is only one end-of-run summary, There were undefined references, and both a failed \ref and a failed \cite raise the same flag. So a message about “undefined references” may well be about a citation.
% first run
LaTeX Warning: Reference `nope' on page 1 undefined on input line 3.
LaTeX Warning: Reference `sec:real' on page 1 undefined on input line 5.
LaTeX Warning: There were undefined references.
LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.
% second run -- sec:real is resolved, nope is a real problem
LaTeX Warning: Reference `nope' on page 1 undefined on input line 3.
LaTeX Warning: There were undefined references.| Message | What it means | What to do |
|---|---|---|
Label(s) may have changed | the numbers have not settled yet | compile again — that is all |
Reference `x' ... undefined | \label{x} is not in the .aux | if it survives a second pass, suspect the spelling or the placement |
There were undefined references | some \ref or \cite did not resolve | read the individual warnings above it |
Label `x' multiply defined | the same label occurs twice or more | make it unique. It only appears from the second run onward |
Citation `x' ... undefined | that entry is not in the .bbl | run bibtex or biber, then compile twice more |
rerunfilecheck: File ... has changed | hyperref’s bookmark file changed | compile again |
When ?? survives two passes
It means the label really is not in the .aux. Checking takes a second: open the .aux and search for \newlabel{, followed by the name. If it is absent, the problem is at the \label end; if it is present and you still get ??, the problem is a spelling difference at the \ref end. Incidentally, the ?? is printed in bold on purpose. The kernel’s \@setref writes \nfss@text{\reset@font\bfseries ??} — deliberately bold so that it cannot be overlooked, which is why it jumps out even from a printed draft. The typical reasons a label never reaches the .aux are below.
- A spelling difference.
\label{fig:setup}and\ref{fig:Setup}are different labels; names are case-sensitive. - The file is excluded by
\includeonly. Labels in an excluded file are never written out, so references to them stay at??. While the exclusion is in force,??is the correct behaviour. - A stale or corrupted
.aux. This follows an interrupted run, or a change of class or package. Delete.aux,.tocand.out, then compile twice. - The
\labelsits inside a moving argument. Written directly into a heading or caption argument, it can be copied into the.tocand mean something else there. Putting it after\caption, outside its braces, is the safe form. - You are compiling the wrong file. In a multi-file project, compiling a child on its own does not update the parent’s
.aux. Always build from the parent. - The citation key is not in the
.bib. That shows up as[?]rather than??; checkbibtex’s own output forI didn’t find a database entry.
A \label before \caption prints the wrong number, silently
Always put \label after \caption. Put it before and you get no error, no warning, and a completely different number in print. This is measurable. Take a document with three \section commands and two figures, put \label before \caption in the first and after it in the second, compile twice, and the .aux reads: \newlabel{fig:before}{{3}{1}{}{}{}} and \newlabel{fig:after}{{2}{1}{}{}{}}. The first should have been Figure 1, but it recorded 3 — the number of the preceding section. And LaTeX issued zero warnings. The PDF builds cleanly and the text confidently says “Figure 3”. The mechanism: \label records the value of whatever counter is currently in force, but switching that counter to figure and stepping it is \caption’s job (it calls \refstepcounter). Before \caption, the most recent \refstepcounter was the one performed by \section, so the section number gets written down. This is the kind of bug you discover when a referee writes “you say see Figure 3, but Figure 3 is something else” — which is exactly why the rule \label immediately after \caption is worth memorising.
\begin{figure}[h]
\includegraphics{fig.pdf}
\caption{The right way round}
\label{fig:ok} % after \caption -- records the figure number
\end{figure}
\begin{figure}[h]
\label{fig:broken} % before \caption -- records the SECTION number
\includegraphics{fig.pdf}
\caption{Silently wrong}
\end{figure}\label inside environments: \item, equation, \section*
There is only one rule: put \label immediately after the command that steps the counter. In enumerate that is right after \item; for an equation it is inside the environment; for a section it is right after \section{…}. Here too, mistakes are silent. Put \label{it:bad} straight after \begin{enumerate}, before the first \item, compile twice, and the .aux records \newlabel{it:bad}{{1}{1}{}{}{}} — not an item number but 1, the number of the preceding section. Again, zero warnings. The same happens with \section*{…}: a starred heading does not step a counter, so a \label after it picks up the number of the last numbered section before it. To reference a starred heading, pair it with \phantomsection (from hyperref) and \addcontentsline, or design the document so it is not referenced. The widespread habit of prefixing label names with fig:, tab:, sec:, eq:, it: is not only about tidiness: writing \ref{fig:x} makes your own intention visible on the page — you meant to point at a figure. If the number that comes out is not a figure’s, the prefix is what lets you notice.
Label ... multiply defined only shows up from the second run
The same \label{x} exists in two or more places, and \ref{x} points at one of them — the one read last. And it has one property worth knowing: on a first run straight after deleting the .aux, this warning does not appear at all. Measured here, a single pass with no .aux present reported zero multiply defined messages. The warning is raised at the start of the second run, when LaTeX reads the .aux back and finds itself defining an already-defined label. So “I compiled once and saw no warning” is not evidence that your labels are unique. At the end of the document there is also a summary, LaTeX Warning: There were multiply-defined labels. The cause is nearly always copy-paste: duplicating a per-chapter file, \include-ing the same file twice, or a subfiles document pulled in from both parent and child. The preventive habit is a per-file prefix — intro:fig:setup — because then a label pasted into another chapter is wrong to the eye.
Citation ... undefined and the BibTeX / Biber run order
If a citation is stuck at [?], the job needs four runs: pdflatex, bibtex, pdflatex, pdflatex. Cross-references need two, but citations need four because another program has to run in the middle. The first pdflatex writes the list of cited keys into the .aux and logs No file document.bbl. alongside Citation ... undefined. Then bibtex matches that key list against your .bib and produces a .bbl, the formatted bibliography. The third run of pdflatex reads the .bbl for the first time, assigns a number to each entry and writes those numbers into the .aux — at which point the \cite commands in the body are still unresolved. Only the fourth run fills them in. In a real log, the third run still showed Citation ... undefined together with Label(s) may have changed. Rerun to get cross-references right., and the fourth was clean. With biblatex you call biber instead of bibtex, but the shape of the sequence is the same. Cite a key that does not exist and bibtex tells you so: Warning--I didn’t find a database entry for "missingkey". For this class of problem, reading bibtex’s output rather than LaTeX’s is what settles it.
pdflatex document # writes the cited keys into document.aux
bibtex document # reads document.aux + refs.bib, writes document.bbl
pdflatex document # reads the .bbl, numbers the entries
pdflatex document # finally resolves every \cite in the text
# with biblatex, swap the second line for:
# biber documentChoosing between \ref, \eqref, \cref, \nameref, \vref — and the load order
Bare \ref prints only a number. The word “Figure” or “Equation” and any parentheses are yours to type, and anything typed by hand eventually drifts out of sync. A layer of commands exists to close that gap, listed in the table below — but the load order is strict. cleveref must come after hyperref and also after varioref. Get it wrong and cleveref.sty diagnoses itself: ! Package cleveref Error: cleveref must be loaded after hyperref!. or ! Package cleveref Error: cleveref must be loaded after varioref!. (both reproduced here). The correct order is hyperref → varioref → cleveref. As practical guidance, for a new document, standardising on cleveref causes the fewest accidents: \cref{eq:e} gives “eq. (1)” and \Cref{sec:s} gives “Section 1”, supplying the right word for each kind of target, so reshuffling the structure never leaves stale wording behind. In an inherited multi-author manuscript, by contrast, it is more realistic to accept a mixture and expect co-authors to keep typing \ref.
| Command | Sample output | Provided by / caveat |
|---|---|---|
\ref | 1 | the kernel; number only. Becomes a link if hyperref is loaded |
\pageref | 1 | the kernel; the second .aux field, that is, the page |
\eqref | (1) | amsmath; an equation number with its parentheses |
\cref | eq. (1) | cleveref; supplies the word matching the target type |
\Cref | Section 1 | cleveref; capitalised form for the start of a sentence |
\autoref | section 1 | hyperref; simpler than \cref and cannot join ranges |
\nameref | The section | nameref, loaded by hyperref; prints the heading text |
\vref | 1 on the previous page | varioref; the number alone on the same page, plus a page phrase when the target is elsewhere |
% load order matters: hyperref, then varioref, then cleveref
\usepackage{amsmath}
\usepackage{hyperref}
\usepackage{varioref}
\usepackage{cleveref} % must come last of the three