Runaway argument

Runaway argument? est la seule erreur LaTeX dont le numéro de ligne est à ne pas croire — et parfois il n’y a aucun numéro de ligne. Omettez une accolade fermante } et TeX part à sa recherche, avalant votre texte au passage, pour ne crier qu’une fois qu’il a tout avalé. Ce qu’il signale alors n’est pas l’endroit de la faute, mais celui où il est arrivé au bout. En échange, TeX réimprime exactement le texte qu’il a avalé : c’est la ligne juste après Runaway argument?, et c’est là la vraie carte. Cette page explique comment la lire, pourquoi le message cite un nom que vous n’avez jamais tapé comme ! Paragraph ended before \@sect was complete, et comment se servir de \newcommand* comme d’un fil-piège délibéré.

Lire le runaway text, pas le numéro de ligne

La ligne qui suit Runaway argument? commence exactement un caractère après l’accolade que vous n’avez pas fermée. Cherchez ses premiers mots dans l’éditeur et vous tenez le { égaré. C’est plus rapide et bien plus sûr que de fixer le numéro de ligne. Voici une sortie de log réelle pour un \textbf{ non fermé.

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

Deux détails méritent l’attention. D’abord le \ETC. final : la marque par laquelle TeX signale que le texte avalé était trop long et a été coupé à la largeur de l’écran. Ensuite, la dernière ligne n’est pas un numéro comme l.6 mais le nom du fichier, <*> t6.tex. Cette forme signifie que TeX n’avait plus rien à lire : il est allé jusqu’à la fin du fichier, et l’accolade { égarée se trouve donc bien plus haut. Un numéro de ligne n’apparaît que si quelque chose a arrêté la fuite en chemin.

Paragraph ended before ... was complete : une ligne vide dans un argument court

Le message signifie qu’une ligne vide se trouve à l’intérieur d’un argument. Pour TeX, une ligne vide n’est pas un blanc mais un token nommé \par, et \par est interdit dans un argument « court », c’est-à-dire l’argument d’une macro définie sans \long. Si une ligne vide se glisse dans un \section{...} là où vous ne vouliez qu’un retour à la ligne, vous obtenez une fuite alors même que la } est bien présente.

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}

Vous n’avez certainement jamais tapé le nom \@sect. En réalité, \section est lui-même défini \long et laisse passer une ligne vide — c’est la macro interne qui prend le relais, \@sect, qui n’est pas \long (un \show sous TeX Live 2024 le confirme). Le nom cité dans le message n’est pas la commande que vous avez tapée, mais la macro interne qui collectait réellement l’argument. Des noms tout aussi inconnus apparaissent autour de \caption, \footnote et de la table des matières. Ne vous laissez pas désarçonner : lisez plutôt la ligne Runaway argument?.

Pourquoi \par est purement et simplement interdit dans un argument

Cette restriction n’est pas là pour gêner : elle a été introduite exprès pour attraper les accolades fermantes oubliées. Le TeX by Topic de Victor Eijkhout, livré avec TeX Live, dit de la règle interdisant \par dans les arguments qu’elle « is useful … in locating forgotten closing braces », et ajoute : « the empty line generates a \par, which most of the times means that a closing brace has been forgotten ». Autrement dit, un argument court est un cran de sûreté qui arrête la fuite tôt. Sans cette règle, une seule { oubliée suffirait à faire avaler tout un document à TeX, en silence et sans le moindre indice.

Une petite expérience montre à quel point le mécanisme est littéral. Ce que TeX refuse, c’est le token portant le nom \par lui-même, et non l’idée de terminer un paragraphe. \endgraf est un alias au comportement identique à \par ; l’écrire dans un argument court ne provoque pourtant rien, alors qu’un \par au même endroit déclenche aussitôt ! Paragraph ended before ... was complete. TeX se contente de comparer des noms de tokens — et c’est précisément ce qui fait d’une ligne vide, blanc par ailleurs insignifiant, un signal qu’il peut détecter à coup sûr.

Ce qui le distingue de File ended while scanning use of ...

Deux lignes différentes peuvent suivre Runaway argument?, et elles indiquent jusqu’où la fuite est allée. Arrêtée en chemin par une ligne vide, vous obtenez Paragraph ended before ... was complete ; jamais arrêtée, vous obtenez File ended while scanning use of .... Un indice plus fin se trouve une ligne plus bas : <to be read again> \par signifie que TeX a lu un \par issu d’une ligne vide et l’a repoussé ; <inserted text> \par signifie qu’il n’avait plus rien à lire et a inséré un \par de son cru. Le premier dit que la cause est proche, le second qu’elle est lointaine.

MessageSignificationCe que le log désigne
Runaway argument?l’argument n’a jamais été terminé ; le texte avalé suit toujours sur la ligne suivantele début de cette ligne se situe juste après la { non fermée
Paragraph ended before ... was completeune ligne vide (un \par) s’est glissée dans un argument courtle numéro de la ligne vide ; la { se trouve un peu au-dessus
File ended while scanning use of ...aucune } n’est apparue jusqu’à la fin du fichiernon pas un numéro de ligne mais <*> nomfichier ; la { est bien plus haut

Se servir de \newcommand* comme d’un fil-piège

\newcommand crée une macro \long, \newcommand* en crée une courte. Un \show affiche \long macro: pour la première et un simple macro: pour la seconde. La différence éclate lors d’une fuite. Oubliez l’accolade fermante d’une macro définie sans étoile et TeX enjambe les lignes vides jusqu’à la fin du fichier, pour terminer sur ! Emergency stop. sans le moindre PDF. Avec l’étoile, il s’arrête à la première ligne vide, nomme votre macro, et la compilation aboutit malgré tout. Ce n’est pas une affaire de quelques lignes de log : c’est la différence entre une zone suspecte de quelques dizaines de lignes et le document entier.

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 règle pratique est simple : définissez avec \newcommand* toute macro dont l’argument n’a pas besoin de contenir des paragraphes entiers. Titres, termes, unités, étiquettes courtes — cela couvre la plupart des macros qu’on écrit soi-même. Réservez la forme sans étoile aux macros censées recevoir des paragraphes, comme le corps d’un encadré. Ce que signifie l’étoile en elle-même et son rapport à \renewcommand relèvent de la page « Définir des macros ». Notez enfin que placer \verb ou un environnement verbatim dans un argument casse d’une tout autre façon : la raison figure sur la page « Verbatim ».

Comment retrouver concrètement l’accolade manquante

Cherchez d’abord le début du runaway text ; si cela ne donne rien, lisez ce qu’il contient. Le texte avalé renferme souvent quelque chose qui n’a rien à faire dans un argument, et cela délimite la zone. Si \begin {document} apparaît dans le runaway text, par exemple, l’accolade non fermée est dans le préambule — oublier de fermer le corps d’un \newcommand produit exactement cette image. Si \end {document} apparaît, la fuite a atteint la fin du document. Une fois le quartier repéré, l’appariement d’accolades de l’éditeur devient précieux : placez le curseur sur une { suspecte et voyez où atterrit sa partenaire. Si cela ne suffit toujours pas, commentez la moitié du document, recompilez, et coupez encore en deux la moitié qui échoue ; quelques tours suffisent toujours.

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