Runaway argument

Runaway argument? es el único error de LaTeX cuyo número de línea no hay que creer, y a veces ni siquiera aparece número de línea. Si omites una } de cierre, TeX sale a buscarla tragándose el texto por el camino y solo grita cuando ya no queda nada por tragar. Lo que informa entonces no es dónde está el fallo, sino dónde se quedó sin sitio. A cambio, TeX reimprime exactamente el texto que se tragó: es la línea justo después de Runaway argument?, y ese es el mapa de verdad. Esta página explica cómo leerlo, por qué el mensaje nombra algo que nunca escribiste como ! Paragraph ended before \@sect was complete, y cómo usar \newcommand* como cable trampa a propósito.

Lee el runaway text, no el número de línea

La línea que sigue a Runaway argument? empieza exactamente un carácter después de la llave que no cerraste. Busca sus primeras palabras en el editor y ya tienes el { perdido. Es más rápido y mucho más fiable que mirar el número de línea. Abajo hay salida de log real de un \textbf{ sin cerrar.

terminal
Runaway argument?
{an important point that never closes. Another sentence on the next l\ETC.
! File ended while scanning use of \textbf .
<inserted text>
                \par
<*> t6.tex

Ahí hay dos detalles dignos de atención. Primero, el \ETC. final: la marca con la que TeX indica que el texto tragado era demasiado largo y se cortó al ancho de la pantalla. Segundo, la última línea no es un número como l.6 sino el nombre del fichero, <*> t6.tex. Esa forma significa que TeX se quedó sin entrada: leyó hasta el final del fichero, así que el { perdido está mucho más arriba. Solo aparece un número de línea cuando algo detuvo la fuga a medio camino.

Paragraph ended before ... was complete: una línea en blanco dentro de un argumento corto

El mensaje significa que hay una línea en blanco dentro de un argumento. Para TeX una línea en blanco no es espacio sino un token llamado \par, y \par no se admite dentro de un argumento «corto», es decir, el de una macro definida sin \long. Así que si una línea en blanco se cuela en un \section{...} donde solo querías un salto de línea, tienes una fuga aunque la } esté perfectamente puesta.

terminal
Runaway argument?
{A heading that runs on
! Paragraph ended before \@sect was complete.
<to be read again>
                   \par
l.5 and on across a blank line}

Seguro que nunca has escrito el nombre \@sect. De hecho, \section está definido como \long y deja pasar una línea en blanco: quien no es \long es la macro interna que se hace cargo del trabajo, \@sect (un \show en TeX Live 2024 lo confirma). El nombre del mensaje no es el comando que escribiste, sino la macro interna que estaba recogiendo el argumento de verdad. Nombres igual de desconocidos asoman alrededor de \caption, \footnote y el índice. No te desconciertes: lee la línea Runaway argument?.

Por qué \par está prohibido en un argumento

La restricción no está para incordiar: se introdujo a propósito para cazar llaves de cierre olvidadas. El TeX by Topic de Victor Eijkhout, que se distribuye con TeX Live, dice de la regla que prohíbe \par en los argumentos que «is useful … in locating forgotten closing braces», y añade: «the empty line generates a \par, which most of the times means that a closing brace has been forgotten». Dicho de otro modo, un argumento corto es un seguro que detiene pronto la fuga. Sin esa regla, una sola { omitida bastaría para que TeX se tragara un documento entero en silencio y se detuviera sin dejar ninguna pista.

Un pequeño experimento revela lo literal que es el mecanismo. Lo que TeX rechaza es el token llamado \par en sí, no la idea de terminar un párrafo. \endgraf es un alias que se comporta igual que \par y, sin embargo, escribirlo dentro de un argumento corto no provoca nada; escribir \par en el mismo sitio dispara al instante ! Paragraph ended before ... was complete. TeX se limita a comparar nombres de tokens, y eso es justamente lo que convierte a una línea en blanco —un espacio por lo demás insignificante— en una señal que puede detectar con seguridad.

En qué se diferencia de File ended while scanning use of ...

Tras Runaway argument? pueden venir dos líneas distintas, y dicen hasta dónde llegó la fuga. Si una línea en blanco la detuvo a medio camino, sale Paragraph ended before ... was complete; si nada la detuvo, sale File ended while scanning use of .... Una pista más fina está una línea más abajo: <to be read again> \par significa que TeX leyó un \par procedente de una línea en blanco y lo devolvió; <inserted text> \par significa que se quedó sin entrada e insertó un \par propio. Lo primero dice que la causa está cerca; lo segundo, que está lejos.

MensajeQué significaAdónde apunta el log
Runaway argument?el argumento nunca se cerró; el texto tragado sigue siempre en la línea siguienteel comienzo de esa línea está justo después del { sin cerrar
Paragraph ended before ... was completeuna línea en blanco (un \par) entró en un argumento cortoel número de la línea en blanco; el { está algo más arriba
File ended while scanning use of ...no apareció ninguna } hasta el final del ficherono un número de línea sino <*> nombrefichero; el { está muy arriba

Usar \newcommand* como cable trampa deliberado

\newcommand crea una macro \long; \newcommand* crea una corta. Un \show imprime \long macro: para la primera y un simple macro: para la segunda. La diferencia se ve con nitidez en una fuga. Olvida la llave de cierre de una macro definida sin asterisco y TeX pasa por encima de las líneas en blanco hasta el final del fichero, para terminar con ! Emergency stop. y ningún PDF. Con asterisco se detiene en la primera línea en blanco, nombra tu macro y la compilación llega hasta el final. No es una diferencia de unas líneas de log: es la diferencia entre una zona sospechosa de unas decenas de líneas y el documento entero.

latex
% short: the runaway stops at the first blank line, and the run survives
\newcommand*{\keyword}[1]{\textbf{#1}}
%   ! Paragraph ended before \keyword was complete.
%   <to be read again>
%                      \par

% long (the default): the runaway reaches end of file
\newcommand{\keyword}[1]{\textbf{#1}}
%   ! File ended while scanning use of \keyword.
%   ! Emergency stop.

La regla práctica es sencilla: define con \newcommand* toda macro cuyo argumento no necesite contener párrafos enteros. Títulos, términos, unidades, etiquetas cortas: eso cubre la mayoría de las macros que uno escribe. Reserva la forma sin asterisco para las macros pensadas para recibir párrafos, como el cuerpo de un recuadro. Qué significa el asterisco en sí y cómo se relaciona con \renewcommand corresponde a la página «Definir macros». Y ten en cuenta que meter \verb o un entorno verbatim dentro de un argumento se rompe de un modo completamente distinto: el motivo está en la página «Verbatim».

Cómo encontrar en la práctica la llave que falta

Busca primero el comienzo del runaway text; si eso no basta, lee lo que hay dentro. El texto tragado suele contener algo que no pinta nada en un argumento, y eso acota la zona. Si en el runaway text aparece \begin {document}, por ejemplo, la llave sin cerrar está en el preámbulo: olvidar cerrar el cuerpo de un \newcommand produce exactamente esa imagen. Si aparece \end {document}, la fuga llegó al final del documento. Una vez acotado el vecindario, el emparejamiento de llaves del editor se gana el sueldo: pon el cursor en un { sospechoso y mira dónde aterriza su pareja. Cuando aun así no alcanza, comenta la mitad del documento, recompila y vuelve a partir por la mitad la parte que siga fallando; con unas pocas rondas siempre se da con ello.

terminal
Runaway argument?
{Hello \begin {document} Body. \end {document}
! File ended while scanning use of \@argdef.