Skip to content

Fix book title-block template path being mangled by pandoc escaping - #14929

Merged
cderv merged 2 commits into
mainfrom
fix/windows-binary-title-block-compile
Sep 23, 2026
Merged

cderv merged 2 commits into
mainfrom
fix/windows-binary-title-block-compile

Conversation

@cderv

@cderv cderv commented Sep 22, 2026

Copy link
Copy Markdown
Member

When a book is rendered to a single-file format (pdf, docx, epub) and Quarto sits under a path whose next segment starts with an ASCII punctuation character, the render aborts with Error compiling template: ...\projects\book\pandoc\title-block.md and pandoc exits 83.

Root Cause

src/project/types/book/book-render.ts hands the title-block template to quarto-post/book.lua by embedding the template's absolute path in a pandoc attribute on a generated code cell (template='...'). Pandoc's markdown reader resolves backslash escapes inside quoted attribute values, so on Windows a backslash followed by punctuation is consumed: D:\a\_temp\quarto\share\... is read back as D:\a_temp\quarto\share\.... compileTemplate in src/resources/filters/common/pandoc.lua then gets nothing from io.open and calls fail().

A backslash followed by a letter survives, which is why a dev checkout resolving to ...\src\resources\... never hits this and the failure first looked specific to the packaged binary. It is not: any install or checkout under a parent directory named _build, .local, -dev and so on reproduces it, including with a dev build. The nightly Windows smoke leg surfaced it because the runner unpacks the binary under D:\a\_temp.

Fix

Escape backslashes and quotes when the attribute value is written, through a new pandocQuotedAttrValue in src/core/pandoc/pandoc-attr.ts. This mirrors what pandoc's own markdown writer does on the way out, where escAttr inside attrsToMarkdown escapes the quote character and the backslash; that logic lives in the Haskell writer and is not exposed to Lua or to callers generating markdown from outside.

The regression test generates the markdown and reads it back with pandoc, asserting the parsed template attribute matches the path that went in, so it covers the round trip that actually breaks rather than the escaping helper in isolation.

Alternatives considered

Normalizing the path with pathWithForwardSlashes (as pandocMetadataPath already does for paths handed to filters and includes) fixes the reported failure and follows existing convention, but it addresses only the backslash. A path containing an apostrophe stays broken, and it is broken worse and on every platform: the quote closes the attribute value early, the fenced block stops parsing as a code block, and pandoc degrades the whole thing to an inline code span holding the literal attribute text plus the chapter body. book.lua then never sees a .quarto-title-block cell, so there is no error at all, just missing content. /home/o'brien/... is enough to trigger it. Escaping covers both cases with one transform.

Passing the template path as a filter param instead, the way ipynb already feeds the same compileTemplate (param('ipynb-title-block'), set in src/format/ipynb/format-ipynb.ts), would keep the path out of the document entirely and is arguably the better shape. It was left out of this change because it adds formatExtras plumbing to the book project type for what is a constant resource path, and because it would not remove the need for an escaper: createMarkdownTitle, a few lines away in the same file, re-emits user-authored heading attributes as text and escapes only the double quote today. That site and the equivalent gap in pandocNativeStr, which omits the backslash from its escape chain, are tracked separately.

@posit-snyk-bot

posit-snyk-bot commented Sep 22, 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.

@cderv
cderv force-pushed the fix/windows-binary-title-block-compile branch from e81f704 to c995a61 Compare September 23, 2026 12:24
The book renderer hands the title-block template to book.lua by embedding the
template's absolute path in a pandoc attribute on a generated code cell
(template='...'). Pandoc's markdown reader resolves backslash escapes inside
quoted attribute values, so a Windows path whose next segment starts with an
ASCII punctuation character silently loses that separator when the generated
markdown is read back: D:\a\_temp\...\share becomes D:\a_temp\...\share, the
Lua side's io.open finds nothing, and the whole render aborts with "Error
compiling template".

Nothing exotic is needed to hit this - any install or checkout under a parent
directory named _build, .local, -dev and so on reproduces it. The nightly
Windows smoke leg started failing on the book fixtures because the runner
unpacks quarto under D:\a\_temp.

Escaping the value where it is produced, rather than converting the path to
forward slashes, also covers a path containing a quote character.

The regression test drives the generated markdown back through pandoc and
compares the parsed attribute against the path that went in, so it exercises
the actual round trip on every platform rather than asserting on the escaping
itself.
@cderv
cderv force-pushed the fix/windows-binary-title-block-compile branch from c995a61 to 3ac49ff Compare September 23, 2026 16:32
@cderv
cderv merged commit cc17224 into main Sep 23, 2026
51 checks passed
@cderv
cderv deleted the fix/windows-binary-title-block-compile branch September 23, 2026 18:28
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.

2 participants