I have noticed an uncommon but annoying glitch when using LaTeX align environments in quarto documents.
In a small fraction, maybe 10%, of the cases using align, the renderer copies the last line of LaTeX code before \end{align}
, but starting with the character one space ahead of the closing right curly brace in the following line. When rendering to pdf, this extra text crashes the pdf generator.
A crude workaround is to add another line at the end of the environment, with nothing but a comment character ('%'). However, this still results in an extraneous '\end{align}
' in the pdf document. If the comment character is in column 12 or beyond (past the end of the \end{align}
below it), it also is reproduced in the pdf.
An example:
---
title: "AlignBugTest1"
format:
pdf:
pdf-engine: pdflatex
keep-tex: true
include-in-header:
- text: |
\usepackage{amsmath}
\newcommand{\bx}{\mathbf{x}}
\newcommand{\by}{\mathbf{y}}
\newcommand{\bS}{\mathbf{\Sigma}}
\newcommand{\bmu}{\boldsymbol{\mu}}
---
\begin{align}
& \Big( \big( \bmu^T \bS^{-1}\ |\ \alpha - \bmu^T \bS^{-1} \mathbf{1}_d
\big) - \mathbf{1}_{d+1}^T \Big) \log{(\bx)} \notag \\
= & \left( \left[ \bmu^T \bS^{-1}\ +
\Big(\frac{\alpha}{d+1} - \frac{\alpha}{d+1}\Big)\ \mathbf{1}_d^T \Big|\
\Big(\frac{d\, \alpha}{d+1} + \frac{\alpha}{d+1} \Big) -
\bmu^T \bS^{-1} \mathbf{1}_d
\right] - \mathbf{1}_{d+1}^T \right)
\log{(\bx)} \notag \\
= & \left( \bmu^T \bS^{-1}\ - \label{eq:AlphaTrans}
\frac{\alpha}{d+1}\ \mathbf{1}_d^T \right) \by +
\left( \frac{\alpha}{d+1} - 1 \right) \sum_{i=1}^{d+1} \log{(x_i)}
\end{align}
Rendering this file in RStudio gives the following console output:
==> quarto preview AlignBugTest1.qmd --to pdf --no-watch-inputs --no-browse
pandoc
to: latex
output-file: AlignBugTest1.tex
standalone: true
pdf-engine: pdflatex
variables:
graphics: true
tables: true
default-image-extension: pdf
metadata
documentclass: scrartcl
classoption:
- DIV=11
- numbers=noendperiod
papersize: letter
header-includes:
- '\KOMAoption{captions}{tableheading}'
block-headings: true
title: AlignBugTest1
Rendering PDF
running pdflatex - 1
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
updating tlmgr
updating existing packages
ERROR:
compilation failed- error
Missing $ inserted.
<inserted text>
$
l.180 \end{align}t( \frac{\alpha}{d+1}
- 1 \right) \sum\_\{i=1\}\^{}\{d+1\}
You may need to $ $ around an expression in this file.
see AlignBugTest1.log for more information.
The same error message at the bottom is found at the bottom of the .log
file as well.
Here is the generated .tex
file:
% Options for packages loaded elsewhere
\PassOptionsToPackage{unicode}{hyperref}
\PassOptionsToPackage{hyphens}{url}
\PassOptionsToPackage{dvipsnames,svgnames,x11names}{xcolor}
%
\documentclass[
letterpaper,
DIV=11,
numbers=noendperiod]{scrartcl}
\usepackage{amsmath,amssymb}
\usepackage{iftex}
\ifPDFTeX
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{textcomp} % provide euro and other symbols
\else % if luatex or xetex
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
\fi
\usepackage{lmodern}
\ifPDFTeX\else
% xetex/luatex font selection
\fi
% Use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\IfFileExists{microtype.sty}{% use microtype if available
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
\makeatletter
\@ifundefined{KOMAClassName}{% if non-KOMA class
\IfFileExists{parskip.sty}{%
\usepackage{parskip}
}{% else
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}}
}{% if KOMA class
\KOMAoptions{parskip=half}}
\makeatother
\usepackage{xcolor}
\setlength{\emergencystretch}{3em} % prevent overfull lines
\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
% Make \paragraph and \subparagraph free-standing
\makeatletter
\ifx\paragraph\undefined\else
\let\oldparagraph\paragraph
\renewcommand{\paragraph}{
\@ifstar
\xxxParagraphStar
\xxxParagraphNoStar
}
\newcommand{\xxxParagraphStar}[1]{\oldparagraph*{#1}\mbox{}}
\newcommand{\xxxParagraphNoStar}[1]{\oldparagraph{#1}\mbox{}}
\fi
\ifx\subparagraph\undefined\else
\let\oldsubparagraph\subparagraph
\renewcommand{\subparagraph}{
\@ifstar
\xxxSubParagraphStar
\xxxSubParagraphNoStar
}
\newcommand{\xxxSubParagraphStar}[1]{\oldsubparagraph*{#1}\mbox{}}
\newcommand{\xxxSubParagraphNoStar}[1]{\oldsubparagraph{#1}\mbox{}}
\fi
\makeatother
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}\usepackage{longtable,booktabs,array}
\usepackage{calc} % for calculating minipage widths
% Correct order of tables after \paragraph or \subparagraph
\usepackage{etoolbox}
\makeatletter
\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
\makeatother
% Allow footnotes in longtable head/foot
\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
\makesavenoteenv{longtable}
\usepackage{graphicx}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
% Scale images if necessary, so that they will not overflow the page
% margins by default, and it is still possible to overwrite the defaults
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
% Set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother
\usepackage{amsmath}
\newcommand{\bx}{\mathbf{x}}
\newcommand{\by}{\mathbf{y}}
\newcommand{\bS}{\mathbf{\Sigma}}
\newcommand{\bmu}{\boldsymbol{\mu}}
\KOMAoption{captions}{tableheading}
\makeatletter
\@ifpackageloaded{caption}{}{\usepackage{caption}}
\AtBeginDocument{%
\ifdefined\contentsname
\renewcommand*\contentsname{Table of contents}
\else
\newcommand\contentsname{Table of contents}
\fi
\ifdefined\listfigurename
\renewcommand*\listfigurename{List of Figures}
\else
\newcommand\listfigurename{List of Figures}
\fi
\ifdefined\listtablename
\renewcommand*\listtablename{List of Tables}
\else
\newcommand\listtablename{List of Tables}
\fi
\ifdefined\figurename
\renewcommand*\figurename{Figure}
\else
\newcommand\figurename{Figure}
\fi
\ifdefined\tablename
\renewcommand*\tablename{Table}
\else
\newcommand\tablename{Table}
\fi
}
\@ifpackageloaded{float}{}{\usepackage{float}}
\floatstyle{ruled}
\@ifundefined{c@chapter}{\newfloat{codelisting}{h}{lop}}{\newfloat{codelisting}{h}{lop}[chapter]}
\floatname{codelisting}{Listing}
\newcommand*\listoflistings{\listof{codelisting}{List of Listings}}
\makeatother
\makeatletter
\makeatother
\makeatletter
\@ifpackageloaded{caption}{}{\usepackage{caption}}
\@ifpackageloaded{subcaption}{}{\usepackage{subcaption}}
\makeatother
\ifLuaTeX
\usepackage{selnolig} % disable illegal ligatures
\fi
\usepackage{bookmark}
\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
\urlstyle{same} % disable monospaced font for URLs
\hypersetup{
pdftitle={AlignBugTest1},
colorlinks=true,
linkcolor={blue},
filecolor={Maroon},
citecolor={Blue},
urlcolor={Blue},
pdfcreator={LaTeX via pandoc}}
\title{AlignBugTest1}
\author{}
\date{}
\begin{document}
\maketitle
\begin{align}
& \Big( \big( \bmu^T \bS^{-1}\ |\ \alpha - \bmu^T \bS^{-1} \mathbf{1}_d
\big) - \mathbf{1}_{d+1}^T \Big) \log{(\bx)} \notag \\
= & \left( \left[ \bmu^T \bS^{-1}\ +
\Big(\frac{\alpha}{d+1} - \frac{\alpha}{d+1}\Big)\ \mathbf{1}_d^T \Big|\
\Big(\frac{d\, \alpha}{d+1} + \frac{\alpha}{d+1} \Big) -
\bmu^T \bS^{-1} \mathbf{1}_d
\right] - \mathbf{1}_{d+1}^T \right)
\log{(\bx)} \notag \\
= & \left( \bmu^T \bS^{-1}\ - \label{eq:AlphaTrans}
\frac{\alpha}{d+1}\ \mathbf{1}_d^T \right) \by +
\left( \frac{\alpha}{d+1} - 1 \right) \sum_{i=1}^{d+1} \log{(x_i)}
\end{align}t( \frac{\alpha}{d+1} - 1 \right) \sum\_\{i=1\}\^{}\{d+1\}
\log{(x_i)} \textbackslash end\{align\}
\end{document}
To me, only the last 25 lines or so are relevant, but I included the whole thing in case some of the black-box code generation has any clues for those more savvy than me. ( I removed a few blank lines near the end of the .tex
document for clarity)
Now here is my workaround in action. Note the last line in the align
environment:
---
title: "AlignBugTest2"
format:
pdf:
pdf-engine: pdflatex
keep-tex: true
include-in-header:
- text: |
\usepackage{amsmath}
\newcommand{\bx}{\mathbf{x}}
\newcommand{\by}{\mathbf{y}}
\newcommand{\bS}{\mathbf{\Sigma}}
\newcommand{\bmu}{\boldsymbol{\mu}}
---
\begin{align}
& \Big( \big( \bmu^T \bS^{-1}\ |\ \alpha - \bmu^T \bS^{-1} \mathbf{1}_d
\big) - \mathbf{1}_{d+1}^T \Big) \log{(\bx)} \notag \\
= & \left( \left[ \bmu^T \bS^{-1}\ +
\Big(\frac{\alpha}{d+1} - \frac{\alpha}{d+1}\Big)\ \mathbf{1}_d^T \Big|\
\Big(\frac{d\, \alpha}{d+1} + \frac{\alpha}{d+1} \Big) -
\bmu^T \bS^{-1} \mathbf{1}_d
\right] - \mathbf{1}_{d+1}^T \right)
\log{(\bx)} \notag \\
= & \left( \bmu^T \bS^{-1}\ - \label{eq:AlphaTrans}
\frac{\alpha}{d+1}\ \mathbf{1}_d^T \right) \by +
\left( \frac{\alpha}{d+1} - 1 \right) \sum_{i=1}^{d+1} \log{(x_i)}
%
\end{align}
This renders successfully...
==> quarto preview AlignBugTest2.qmd --to pdf --no-watch-inputs --no-browse
pandoc
to: latex
output-file: AlignBugTest2.tex
standalone: true
pdf-engine: pdflatex
variables:
graphics: true
tables: true
default-image-extension: pdf
metadata
documentclass: scrartcl
classoption:
- DIV=11
- numbers=noendperiod
papersize: letter
header-includes:
- '\KOMAoption{captions}{tableheading}'
block-headings: true
title: AlignBugTest2
Rendering PDF
running pdflatex - 1
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
running pdflatex - 2
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
Output created: AlignBugTest2.pdf
Watching files for changes
Browse at http://localhost:6069/web/viewer.html
pandoc
to: latex
output-file: AlignBugTest2.tex
standalone: true
pdf-engine: pdflatex
variables:
graphics: true
tables: true
default-image-extension: pdf
metadata
documentclass: scrartcl
classoption:
- DIV=11
- numbers=noendperiod
papersize: letter
header-includes:
- '\KOMAoption{captions}{tableheading}'
block-headings: true
title: AlignBugTest2
Rendering PDF
running pdflatex - 1
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
running pdflatex - 2
This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
Output created: AlignBugTest2.pdf
Watching files for changes
Here is the generated .tex
file.
% Options for packages loaded elsewhere
\PassOptionsToPackage{unicode}{hyperref}
\PassOptionsToPackage{hyphens}{url}
\PassOptionsToPackage{dvipsnames,svgnames,x11names}{xcolor}
%
\documentclass[
letterpaper,
DIV=11,
numbers=noendperiod]{scrartcl}
\usepackage{amsmath,amssymb}
\usepackage{iftex}
\ifPDFTeX
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{textcomp} % provide euro and other symbols
\else % if luatex or xetex
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
\fi
\usepackage{lmodern}
\ifPDFTeX\else
% xetex/luatex font selection
\fi
% Use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\IfFileExists{microtype.sty}{% use microtype if available
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
\makeatletter
\@ifundefined{KOMAClassName}{% if non-KOMA class
\IfFileExists{parskip.sty}{%
\usepackage{parskip}
}{% else
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}}
}{% if KOMA class
\KOMAoptions{parskip=half}}
\makeatother
\usepackage{xcolor}
\setlength{\emergencystretch}{3em} % prevent overfull lines
\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
% Make \paragraph and \subparagraph free-standing
\makeatletter
\ifx\paragraph\undefined\else
\let\oldparagraph\paragraph
\renewcommand{\paragraph}{
\@ifstar
\xxxParagraphStar
\xxxParagraphNoStar
}
\newcommand{\xxxParagraphStar}[1]{\oldparagraph*{#1}\mbox{}}
\newcommand{\xxxParagraphNoStar}[1]{\oldparagraph{#1}\mbox{}}
\fi
\ifx\subparagraph\undefined\else
\let\oldsubparagraph\subparagraph
\renewcommand{\subparagraph}{
\@ifstar
\xxxSubParagraphStar
\xxxSubParagraphNoStar
}
\newcommand{\xxxSubParagraphStar}[1]{\oldsubparagraph*{#1}\mbox{}}
\newcommand{\xxxSubParagraphNoStar}[1]{\oldsubparagraph{#1}\mbox{}}
\fi
\makeatother
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}\usepackage{longtable,booktabs,array}
\usepackage{calc} % for calculating minipage widths
% Correct order of tables after \paragraph or \subparagraph
\usepackage{etoolbox}
\makeatletter
\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
\makeatother
% Allow footnotes in longtable head/foot
\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
\makesavenoteenv{longtable}
\usepackage{graphicx}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
% Scale images if necessary, so that they will not overflow the page
% margins by default, and it is still possible to overwrite the defaults
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
% Set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother
\usepackage{amsmath}
\newcommand{\bx}{\mathbf{x}}
\newcommand{\by}{\mathbf{y}}
\newcommand{\bS}{\mathbf{\Sigma}}
\newcommand{\bmu}{\boldsymbol{\mu}}
\KOMAoption{captions}{tableheading}
\makeatletter
\@ifpackageloaded{caption}{}{\usepackage{caption}}
\AtBeginDocument{%
\ifdefined\contentsname
\renewcommand*\contentsname{Table of contents}
\else
\newcommand\contentsname{Table of contents}
\fi
\ifdefined\listfigurename
\renewcommand*\listfigurename{List of Figures}
\else
\newcommand\listfigurename{List of Figures}
\fi
\ifdefined\listtablename
\renewcommand*\listtablename{List of Tables}
\else
\newcommand\listtablename{List of Tables}
\fi
\ifdefined\figurename
\renewcommand*\figurename{Figure}
\else
\newcommand\figurename{Figure}
\fi
\ifdefined\tablename
\renewcommand*\tablename{Table}
\else
\newcommand\tablename{Table}
\fi
}
\@ifpackageloaded{float}{}{\usepackage{float}}
\floatstyle{ruled}
\@ifundefined{c@chapter}{\newfloat{codelisting}{h}{lop}}{\newfloat{codelisting}{h}{lop}[chapter]}
\floatname{codelisting}{Listing}
\newcommand*\listoflistings{\listof{codelisting}{List of Listings}}
\makeatother
\makeatletter
\makeatother
\makeatletter
\@ifpackageloaded{caption}{}{\usepackage{caption}}
\@ifpackageloaded{subcaption}{}{\usepackage{subcaption}}
\makeatother
\ifLuaTeX
\usepackage{selnolig} % disable illegal ligatures
\fi
\usepackage{bookmark}
\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
\urlstyle{same} % disable monospaced font for URLs
\hypersetup{
pdftitle={AlignBugTest2},
colorlinks=true,
linkcolor={blue},
filecolor={Maroon},
citecolor={Blue},
urlcolor={Blue},
pdfcreator={LaTeX via pandoc}}
\title{AlignBugTest2}
\author{}
\date{}
\begin{document}
\maketitle
\begin{align}
& \Big( \big( \bmu^T \bS^{-1}\ |\ \alpha - \bmu^T \bS^{-1} \mathbf{1}_d
\big) - \mathbf{1}_{d+1}^T \Big) \log{(\bx)} \notag \\
= & \left( \left[ \bmu^T \bS^{-1}\ +
\Big(\frac{\alpha}{d+1} - \frac{\alpha}{d+1}\Big)\ \mathbf{1}_d^T \Big|\
\Big(\frac{d\, \alpha}{d+1} + \frac{\alpha}{d+1} \Big) -
\bmu^T \bS^{-1} \mathbf{1}_d
\right] - \mathbf{1}_{d+1}^T \right)
\log{(\bx)} \notag \\
= & \left( \bmu^T \bS^{-1}\ - \label{eq:AlphaTrans}
\frac{\alpha}{d+1}\ \mathbf{1}_d^T \right) \by +
\left( \frac{\alpha}{d+1} - 1 \right) \sum_{i=1}^{d+1} \log{(x_i)}
%
\end{align}\textbackslash end\{align\}
\end{document}
The glitchy code is the second-to-last line of code in the file.
Here is the output. Note the extraneous \end{align}
.
AlignBugTest2.pdf (107.0 KB)
This glitch is very hard to understand. If I comment out the second of the three lines in the environment, the glitch goes away. When I encountered it in other cases, I could rework the code by rewriting, breaking up the environment, etc., but sometimes this was painstaking. Additionally, I could never find a common cause. For example, other cases when using \left[
and \right]
pairs (found in the second line) did not show this issue.
Any assistance/guidance very welcome at this point. Thanks.
Rstudio/quarto info:
RStudio 2024.09.0+375 "Cranberry Hibiscus" Release
(c8fc7aee6dc218d5687553f9041c6b1e5ea268ff, 2024-09-16) for macOS
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)
RStudio/2024.09.0+375 Chrome/124.0.6367.243 Electron/30.4.0 Safari/537.36, Quarto 1.5.57 (/Applications/quarto/bin/quarto)
> packageVersion("tinytex")
[1] ‘0.53’