Missing \begin{document}

! LaTeX Error: Missing \begin{document}. es una rareza entre los errores de LaTeX: un mensaje que miente sobre sí mismo. La mayoría de los documentos que lo producen tienen un \begin{document} perfectamente puesto. La verdad es esta: LaTeX nunca comprueba si \begin{document} está presente. Lo único que comprueba es si ha empezado un párrafo, y deja armada en el preámbulo una trampa que, en ese preciso instante, suelta esta frase. Así que el error hay que leerlo no como «falta \begin{document}» sino como «apareció algo imprimible antes de \begin{document}». Esta página confirma ese mecanismo en el código del núcleo de LaTeX y luego recorre las tres familias de causas: texto perdido, un \maketitle que se quedó en el preámbulo y un solo byte invisible.

Por qué el mensaje miente sobre sí mismo

LaTeX carga \everypar en el preámbulo con \@nodocument, y salta en el instante en que empieza un párrafo. \everypar es el gancho de TeX que se ejecuta cada vez que comienza un párrafo, y un párrafo comienza en cuanto aparece algo imprimible. Las líneas correspondientes de latex.ltx, el propio núcleo de LaTeX, siguen llevando el comentario de sus desarrolladores.

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}»: el comentario lo dice sin rodeos. La tarea de \begin{document} es desarmar esta trampa; la trampa, por su parte, no busca \begin{document} en absoluto. El \nullfont de la línea siguiente responde a la misma idea: durante todo el preámbulo la fuente actual es una que no contiene carácter alguno, de modo que lo impreso por accidente no deja nada en la página. Eso zanja también cómo arreglarlo: lo que hay que buscar no es \begin{document} sino lo imprimible que vino antes. Aun así, comprueba una vez que la línea está realmente ahí y bien escrita: rara pero realmente, un \begin{document} de verdad ausente produce este mismo mensaje. Tras ese vistazo, deja de mirarlo.

El log te entrega el carácter exacto

La línea l.NN se parte justo después del carácter que lo provocó. TeX divide la línea culpable en lo leído y lo no leído, y apila ambas mitades: el final de la mitad superior es el culpable en persona. De ahí la impresión de que una palabra ha quedado cortada en dos: abajo, la T al comienzo de la línea 3 fue lo primero imprimible, abrió un párrafo y la trampa saltó. Ese documento tiene un \begin{document} impecable en la línea 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.

Qué cuenta como imprimible en un preámbulo

Un preámbulo solo admite comandos que registran un valor y no imprimen nada. \usepackage, \title, \author, \date, \newcommand y los ajustes de todo tipo se limitan a almacenar información, así que nunca abren un párrafo. En cambio, todo lo que intenta poner algo en la página produce este error. La frontera no es «¿parece texto del cuerpo?» sino «¿genera salida?», y de ahí esa distinción a primera vista extraña: \title{Mi artículo} es inofensivo y \maketitle no lo es.

  • Texto perdido — una frase a medias bajo \documentclass, o una línea pensada como comentario cuyo % nunca se escribió. Es con diferencia la causa más común.
  • Un \maketitle en el preámbulo — escribirlo junto a \title es un desliz frecuente. \maketitle va después de \begin{document}.
  • Llamar a una macro que emite texto — un \today suelto en el preámbulo, o una macro propia que simplemente se expande a una cadena. Definir esas macros es inofensivo; llamarlas no.
  • Un símbolo de más — un ~ justo después de \usepackage{amsmath}, o un carácter que quedó fuera de una llave sin cerrar. Una } sobrante, en cambio, da ! 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}

Cuando la culpa es de un solo byte invisible

Si has leído el preámbulo tres veces sin encontrar nada imprimible, el culpable es muy probablemente un espacio duro, U+00A0. El fichero utf8enc.dfu de LaTeX contiene la línea \DeclareUnicodeCharacter{00A0}{\nobreakspace}, que define U+00A0 como un espacio que se imprime. Es, por tanto, salida de verdad, y en un preámbulo abre un párrafo. En pantalla no se distingue de un espacio corriente. Se cuela con toda naturalidad: en una línea \usepackage copiada de una página web o de un PDF, con Opción+Espacio en un Mac, con una distribución de teclado francesa. En ese caso, la media línea sobre l.NN tiene un aspecto característico: parece que al final no hay absolutamente nada.

CarácterCómo se cuelaQué ocurre en un preámbulo
U+00A0espacio duro; copiado de la web o de un PDF, Opción+Espacio en Mac, distribuciones francesasse imprime como \nobreakspace, de ahí este error; igual en todos los motores
U+3000espacio ideográfico; tecleado con un método de entrada CJK activo o copiado de texto CJKeste error en xelatex y lualatex; en pdflatex, otro distinto: Unicode character not set up
U+FEFFun BOM; algunos editores de Windows lo añaden al principio de un fichero UTF-8en TeX Live 2024, pdflatex, xelatex y lualatex lo omiten todos. No es la causa

La última fila de esa tabla contradice un consejo muy repetido. Un BOM no es la causa de este error. En TeX Live 2024, un fichero que empieza con BOM pasa por pdflatex, xelatex y lualatex sin siquiera un aviso, incluso cuando el comando file lo declara UTF-8 (with BOM) text. Por eso «vuelve a guardarlo sin BOM» tantas veces no sirve de nada; ese tiempo se aprovecha mejor buscando un U+00A0. De paso: \usepackage[utf8]{inputenc} tampoco hace ya falta, desde que LaTeX News 28 (2018) hizo de UTF-8 la codificación de entrada por defecto. Las codificaciones en sí se tratan en la página «Codificación y saltos de línea».

Encontrar de verdad el byte intruso

Un preámbulo debería ser ASCII puro, así que buscar mecánicamente las líneas con algún carácter no ASCII lo caza al instante. Ahora bien, si lo aplicas al fichero entero, cada línea de texto japonés o chino coincide y el resultado no sirve de nada. El truco está en cortar el fichero por \begin{document} primero. Localizada la línea, sed -n l muestra sus bytes: un U+00A0 aparece como \302\240, lo que zanja la identificación. Después basta con volver a teclear esos dos bytes como un espacio corriente.

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