7

I'm working on a large LaTeX document (over 1000 pages). I'm using \include liberally, and there are 47 .tex files in play. At the end of the run I get these diagnostics:

(\end occurred when \iftrue on line 366 was incomplete)
(\end occurred when \ifnum on line 366 was incomplete) 

The version of TeX I'm using announces itself as follows:

This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2015/dev/Debian) (preloaded format=latex 2015.5.11)  29 DEC 2015 17:28

My question: how do I find the offending command? I've used Awk to print line 366 of each .tex file in the directory, but none of these files seem to have any kind of conditionals there. I've also looked in the .aux files. Local .sty files are not in play because none of them is 366 lines.

Where should I be looking? What should I be looking for? Is there a way to persuade TeX to disgorge the name of the offending file and not just the line number? Perhaps some luatex trickery?

(I don't know how to provide a minimal example. If I did, I probably could solve the problem.)

Alenanno
  • 37,338
  • 4
    Even if the error tells you that the problem occurred in a certain line, it doesn't mean it necessarily occurred at that line. For example: if you define a \newcommand in your preamble (and it has a mistake), and then you use that same command in line 300, then your error will appear on line 300, but it's actually originating in your \newcommand definition in the preamble. – Alenanno Dec 29 '15 at 22:46

3 Answers3

9

If you look at

\tracingifs=2

\ifnum9=9

\stop

with \tracingifs set then the log shows more information:

(./file.tex
LaTeX2e <2016/01/01>
Babel <3.9m> and hyphenation patterns for 79 languages loaded.
{vertical mode: \ifnum: (level 1) entered on line 4}
{\ifvmode: (level 2) entered on line 6}
{\ifnum: (level 3) entered on line 6}
{\fi: \ifnum (level 3) entered on line 6}
{\fi: \ifvmode (level 2) entered on line 6}
{\iftrue: (level 2) entered on line 6}
{\ifx: (level 3) entered on line 6}
{\fi: \ifx (level 3) entered on line 6}
{\fi: \iftrue (level 2) entered on line 6}
{\iffalse: (level 2) entered on line 6}
{\fi: \iffalse (level 2) entered on line 6}
{\iffalse: (level 2) entered on line 6}
{\fi: \iffalse (level 2) entered on line 6}
{internal vertical mode: \ifnum: (level 2) entered on line 6}
{\ifnum: (level 3) entered on line 6}
{\ifvoid: (level 4) entered on line 6}
{\ifvbox: (level 5) entered on line 6}
{\fi: \ifvbox (level 5) entered on line 6}
{\ifx: (level 5) entered on line 6}
{\else: \ifx (level 5) entered on line 6}
{\fi: \ifx (level 5) entered on line 6}
{\ifx: (level 5) entered on line 6}
{\else: \ifx (level 5) entered on line 6}
{\fi: \ifx (level 5) entered on line 6}
{\iffalse: (level 5) entered on line 6}
{\fi: \iffalse (level 5) entered on line 6}
{\iffalse: (level 5) entered on line 6}
{\fi: \iffalse (level 5) entered on line 6}
{\ifx: (level 5) entered on line 6}
{\else: \ifx (level 5) entered on line 6}
{\fi: \ifx (level 5) entered on line 6}
{\else: \ifvoid (level 4) entered on line 6}
{\fi: \ifvoid (level 4) entered on line 6}
{\else: \ifnum (level 3) entered on line 6}
{\fi: \ifnum (level 3) entered on line 6}
{\else: \ifnum (level 2) entered on line 6}
{\fi: \ifnum (level 2) entered on line 6}
{\ifnum: (level 2) entered on line 6}
{\ifdim: (level 3) entered on line 6}
{\else: \ifdim (level 3) entered on line 6}
{\fi: \ifdim (level 3) entered on line 6}
{\else: \ifnum (level 2) entered on line 6}
{\fi: \ifnum (level 2) entered on line 6}
{\ifnum: (level 2) entered on line 6}
{\ifnum: (level 3) entered on line 6}
{\else: \ifnum (level 3) entered on line 6}
{\ifnum: (level 4) entered on line 6}
{\ifnum: (level 5) entered on line 6}
{\fi: \ifnum (level 5) entered on line 6}
{\else: \ifnum (level 4) entered on line 6}
{\fi: \ifnum (level 4) entered on line 6}
{\fi: \ifnum (level 3) entered on line 6}
{\else: \ifnum (level 2) entered on line 6}
{\fi: \ifnum (level 2) entered on line 6}
{\ifnum: (level 2) entered on line 6}
{\else: \ifnum (level 2) entered on line 6}
{\fi: \ifnum (level 2) entered on line 6}
 )
(\end occurred when \ifnum on line 4 was incomplete) 

So you can see it is in this case an unmatched (level 1) \ifnum

Working upwards in the log from the line

    {vertical mode: \ifnum: (level 1) entered on line 4}

you see the first ( shows (./file.tex so it is line 4 of file.tex that has the offending if.

David Carlisle
  • 757,742
2

Try to search the eventual \end{docuement} in the one of files input before main file ...

Abd
  • 21
1

Some tips for large log file:

  • Since it's really hard to look for (file and ) in that case, you can use some LaTeX hook to log some message when the file changes:

    \ExplSyntaxOn
    \seq_new:N \__file_list
    \seq_put_right:Nn \__file_list {\msg_expandable_error:nn{}{this~cannot~happen!}}
    \seq_put_right:Nn \__file_list {<main~file>}
    \AddToHook{file/before}{
        \seq_put_right:NV \__file_list \CurrentFile
        \wlog {enter~file\use_none:n{}::\CurrentFile}
    }
    \AddToHook{file/after}{
        \seq_pop_right:NN \__file_list \__last_file
        \seq_get_right:NN \__file_list \__last_file
        \wlog {return~to~file\use_none:n{}::\__last_file}
    }
    \ExplSyntaxOff
    

    (obviously the effect is, you get a line enter file::X and return to file::X in the log. Search for file::. The \use_none:n {} is to prevent the message from being found while doing macro expansion, if macro logging is enabled.)

  • A "binary search" alternative is to insert a (commented) empty line to some TeX files, then see if the line number increases. (it's "brute force", but works most of the time, except if catcode is weird.)

  • Note that, even if some particular \if is reported as the culprit, it's not necessarily the cause. For example

    \if ... % A
    
    \if ... % B (accidentally inserted)
    
    

    \fi % C

    Clearly the one at B is at fault here, nevertheless TeX will report A is incomplete. And A might be deep buried inside some library code (e.g. if you have incomplete \if within some .sty file this can happen)

  • Generally speaking, it's useful to search for if.* <line number>} (regex) from the end of the file, since you can observe that if there are multiple such \if, the last one will be likely at fault; nevertheless if the first hit is a \fi then skip through one \if.

    Example log

    {\if entered on line X}
    {\else: \if entered on line X}
    {\fi: \if entered on line X}
    

    {\if entered on line X} {\else: \if entered on line X} {\fi: \if entered on line X}

    {\if entered on line X} {\else: \if entered on line X} {\fi: \if entered on line X}

    {\if entered on line X}

    {\if entered on line X} {\else: \if entered on line X} {\fi: \if entered on line X}

    In this example it can be seen that if you search for the log lines from the end backwards, you'll first see a \fi, then skip one \if, then find the offending command immediately. (there's (level X) to partially help with search for matching lines, but no more than that.)

user202729
  • 7,143