Skip to content

Fix cross-referenced longtable PDF failure with endfloat - #14742

Open
cderv wants to merge 3 commits into
mainfrom
fix/14741-longtable-group
Open

Fix cross-referenced longtable PDF failure with endfloat#14742
cderv wants to merge 3 commits into
mainfrom
fix/14741-longtable-group

Conversation

@cderv

@cderv cderv commented Jul 31, 2026

Copy link
Copy Markdown
Member

Since Pandoc 3.8.1, a captionless longtable is wrapped in a {\def\LTcaptype{none} … } brace group so it doesn't step the table counter. Quarto lifts the caption off any cross-referenceable table (#| label: tbl-) before Pandoc writes it, so every such table now takes that captionless path. Quarto supplies its own \caption and strips the \def\LTcaptype{none} (it would clash with the caption package), but until now kept the surrounding braces as harmless.

They are not harmless. With endfloat and \DeclareDelayedFloatFlavor*{longtable}{table}, the environment is read verbatim into the .ttt file and terminated with \end{efloat@float}, so the env/longtable/after hook that footnotehyper's \makesavenoteenv{longtable} installs never fires and its \savenotes \begingroup is left open. Quarto's trailing } is the first token to hit that open group, and compilation fails with Extra }, or forgotten \endgroup.

This is a regression from the Pandoc 3.6.3 → 3.8.3 bump in v1.9.17. It is environment-dependent: the leaked group only exists when footnotehyper.sty is installed, which is why TinyTeX-based CI never caught it.

Fix

src/resources/filters/customnodes/floatreftarget.lua now drops the braces along with the definition — but only when they are provably Pandoc's own wrapper: the preamble is exactly the opening brace and the \def, the postamble is exactly the closing brace, and the raw block holds a single longtable. Otherwise it falls back to stripping the definition alone, as before. That keeps hands off:

  • an author's own \def\LTcaptype{figure} and the group scoping it,
  • a group that scopes more than the definition (e.g. a \setlength), which would leak if unbraced,
  • a raw block carrying two longtable groups, where the two braces belong to different groups.

Fixes #14741

cderv added 2 commits July 31, 2026 15:17
Pandoc 3.8.1+ wraps a captionless table in `{\def\LTcaptype{none} ... }`
so it doesn't step the table counter. Quarto's longtable fixup adds its
own `\caption`, so it strips the definition but kept the braces, on the
assumption they were harmless.

They aren't. Pandoc's LaTeX template does `\makesavenoteenv{longtable}`,
and footnotehyper implements that with `env/longtable/before`/`after`
hooks that `\begingroup`/`\endgroup` around the environment. endfloat's
`\DeclareDelayedFloatFlavor*{longtable}{table}` reads the environment
into the .ttt file and terminates it with `\end{efloat@float}`, so the
`after` hook never fires and the `\savenotes` group stays open. Quarto's
trailing `}` is the first token to meet it, and LaTeX fails with
"Extra }, or forgotten \endgroup".

Drop the braces along with the definition, but only when they are
provably Pandoc's own wrapper: the preamble is the opening brace and the
definition and nothing else (anything else in the group is scoped by it
and would leak), the postamble is the closing brace and nothing else,
and the raw block holds a single longtable (the pattern spans first
\begin to last \end, so with two of them the braces belong to different
groups and removing both unbalances the output). Anything else falls
back to dropping the definition alone, exactly as before.

Rendered output is otherwise unchanged: table numbering,
cross-references and caption placement all come from Quarto's own
`\caption`.

Regression introduced in v1.9.17, which bumped Pandoc 3.6.3 -> 3.8.3.

Fixes #14741
The issue's reprex uses `knitr::kable(longtable = TRUE)`, which under
Quarto defaults to the pipe format - so the cell emits a markdown table
and Pandoc's writer produces the longtable. That is the shape 14741.qmd
covers; this adds the engine version that goes through knitr for real,
plus a second cell with `format = "latex"` for the raw-LaTeX path.
@posit-snyk-bot

posit-snyk-bot commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

The full endfloat/footnotehyper chain lives in #14741 and the per-guard
rationale in the 14741-raw-latex test doc; the inline comment only needs
enough to read the code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug in quarto or pandoc breaks use of the endfloat LaTeX package

2 participants