Missing \begin{document}

! LaTeX Error: Missing \begin{document}. est une rareté parmi les erreurs LaTeX : un message qui ment sur lui-même. La plupart des documents qui la produisent contiennent un \begin{document} parfaitement en place. La vérité, la voici : LaTeX ne vérifie jamais la présence de \begin{document}. Il ne vérifie qu’une chose, si un paragraphe a commencé, et il pose dans le préambule un piège qui, à cet instant précis, sort cette formulation. Il faut donc lire l’erreur non pas comme « il manque \begin{document} » mais comme « quelque chose d’imprimable est apparu avant \begin{document} ». Cette page vérifie ce mécanisme dans les sources du noyau LaTeX, puis parcourt les trois familles de causes : du texte égaré, un \maketitle resté dans le préambule, et un unique octet invisible.

Pourquoi le message ment sur lui-même

LaTeX charge \everypar dans le préambule avec \@nodocument, et cela se déclenche à l’instant où un paragraphe commence. \everypar est le crochet de TeX exécuté à chaque début de paragraphe, et un paragraphe commence dès que quelque chose d’imprimable se présente. Les lignes concernées de latex.ltx, le noyau de LaTeX lui-même, portent encore le commentaire des développeurs.

latex.ltx
\gdef\@nodocument{%
  \@latex@error{Missing \protect\begin{document}}\@ehd}

\everypar{\@nodocument} %% To get an error if text appears before the
\nullfont               %% \begin{document}

« To get an error if text appears before the \begin{document} » — le commentaire le dit sans détour. Le rôle de \begin{document} est de désamorcer ce piège ; le piège, lui, ne cherche nullement \begin{document}. Le \nullfont de la ligne suivante procède de la même idée : pendant tout le préambule, la fonte courante est une fonte qui ne contient aucun caractère, de sorte que ce qui serait imprimé par accident ne laisse rien sur la page. Cela règle aussi la question du remède : ce qu’il faut chercher, ce n’est pas \begin{document} mais l’élément imprimable qui le précède. Vérifiez tout de même une fois que la ligne est bien présente et correctement orthographiée : rarement mais réellement, un \begin{document} véritablement absent produit ce même message. Passé ce coup d’œil, inutile de continuer à le fixer.

Le log vous livre le caractère exact

La ligne l.NN se coupe exactement après le caractère fautif. TeX partage la ligne concernée entre ce qu’il a lu et ce qu’il n’a pas lu, puis empile les deux moitiés : la fin de la moitié supérieure est donc le coupable lui-même. D’où l’impression qu’un mot a été tranché en deux : ci-dessous, le T en tête de la ligne 3 a été le premier élément imprimable, il a ouvert un paragraphe, et le piège s’est déclenché. Ce document comporte un \begin{document} parfaitement en place à la ligne 4.

terminal
! LaTeX Error: Missing \begin{document}.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...

l.3 T
     his line is body text by mistake.

Ce qui compte comme imprimable dans un préambule

Un préambule ne peut contenir que des commandes qui enregistrent une valeur sans rien imprimer. \usepackage, \title, \author, \date, \newcommand et les réglages en tout genre se contentent de stocker de l’information : ils n’ouvrent jamais de paragraphe. En revanche, tout ce qui cherche à poser quelque chose sur la page produit cette erreur. La frontière ne passe pas par « est-ce que cela ressemble à du texte » mais par « est-ce que cela produit une sortie » — d’où cette distinction en apparence bizarre : \title{Mon article} est inoffensif, \maketitle ne l’est pas.

  • Du texte égaré — une phrase inachevée restée sous \documentclass, ou une ligne censée être un commentaire dont le % n’a jamais été tapé. C’est de loin la cause la plus fréquente.
  • Un \maketitle dans le préambule — l’écrire juste à côté de \title est un faux pas courant. \maketitle va après \begin{document}.
  • L’appel d’une macro qui émet du texte — un \today isolé dans le préambule, ou l’une de vos macros qui se contente de se développer en une chaîne. Définir de telles macros est sans danger ; les appeler ne l’est pas.
  • Un signe en trop — un ~ juste après \usepackage{amsmath}, ou un caractère resté hors d’une accolade non fermée. Une } excédentaire donne en revanche ! Too many }.
latex
\documentclass{article}
\title{My Paper}   % safe: records a value, prints nothing
\author{Me}       % safe
\maketitle        % ! LaTeX Error: Missing \begin{document}.
\begin{document}
\maketitle        % this is where it belongs
\end{document}

Quand un seul octet invisible est en cause

Si vous avez relu trois fois le préambule sans y trouver quoi que ce soit d’imprimable, le coupable est très probablement une espace insécable, U+00A0. Le fichier utf8enc.dfu de LaTeX contient la ligne \DeclareUnicodeCharacter{00A0}{\nobreakspace}, qui définit U+00A0 comme une espace qui s’imprime. C’est donc une véritable sortie, et dans un préambule elle ouvre un paragraphe. À l’écran, rien ne la distingue d’une espace ordinaire. Elle s’invite tout naturellement : dans une ligne \usepackage copiée depuis une page web ou un PDF, via Option+Espace sur un Mac, via une disposition de clavier française. Dans ce cas, la demi-ligne au-dessus de l.NN a une allure caractéristique : on dirait qu’il n’y a rien du tout à sa fin.

CaractèreComment il s’introduitCe qui se passe dans un préambule
U+00A0espace insécable ; copie depuis le web ou un PDF, Option+Espace sur Mac, dispositions françaisess’imprime comme \nobreakspace, d’où cette erreur — sur tous les moteurs
U+3000espace idéographique ; frappée avec une méthode de saisie CJK active, ou copiée depuis du texte CJKcette erreur avec xelatex et lualatex ; avec pdflatex, une autre : Unicode character not set up
U+FEFFun BOM ; certains éditeurs Windows en ajoutent un en tête d’un fichier UTF-8sous TeX Live 2024, pdflatex, xelatex et lualatex l’ignorent tous. Ce n’est pas la cause

La dernière ligne de ce tableau contredit un conseil très répandu. Un BOM n’est pas la cause de cette erreur. Sous TeX Live 2024, un fichier commençant par un BOM passe dans pdflatex, xelatex et lualatex sans le moindre avertissement — y compris lorsque la commande file le signale comme UTF-8 (with BOM) text. Voilà pourquoi « réenregistrez sans BOM » reste si souvent sans effet ; mieux vaut consacrer ce temps à chercher un U+00A0. Au passage : \usepackage[utf8]{inputenc} n’est plus nécessaire non plus, LaTeX News 28 (2018) ayant fait de l’UTF-8 l’encodage d’entrée par défaut. Les encodages en tant que tels sont traités sur la page « Encodage et fins de ligne ».

Retrouver concrètement l’octet égaré

Un préambule devrait être en pur ASCII : chercher mécaniquement les lignes contenant un caractère non ASCII le débusque aussitôt. Appliquée au fichier entier, la recherche fait toutefois correspondre chaque ligne de texte japonais ou chinois et ne sert à rien. L’astuce est de couper le fichier à \begin{document} au préalable. Une fois la ligne repérée, sed -n l en affiche les octets : un U+00A0 apparaît sous la forme \302\240, ce qui règle l’identification. Il ne reste plus qu’à retaper ces deux octets en espace ordinaire.

bash
# list preamble lines that contain a non-ASCII character
sed -n '1,/begin{document}/p' paper.tex | LC_ALL=C grep -n '[^ -~]'

# reveal the bytes on a suspect line (U+00A0 shows up as \302\240)
sed -n '3p' paper.tex | sed -n l

# check whether the file carries a byte order mark
file paper.tex