quarto-dev / quarto-dev/quarto-cli
margin-footer / margin-header with markdown/HTML content crashes on Windows with os error 123
@cderv is already working on this.
Since Apr 27, 2026.
- Dominant language
- JavaScript
- Stars
- 6k
- Forks
- 458
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 41
Description
Bug description
On Windows, setting margin-footer (or margin-header) to inline markdown or HTML content that contains characters illegal in Windows paths causes quarto render to crash with os error 123.
This happens because websiteProjectConfig (src/project/types/website/website-config.ts) calls resolveProjectPaths on each margin-footer value, and resolveProjectPaths does a raw existsSync(maybePath) check. On Windows, existsSync throws when the string contains characters like [, ], <, >, |, :, ", ?, *.
On macOS/Linux, existsSync simply returns false for these strings, so the bug is Windows-specific.
Steps to reproduce
Create a Quarto book project with the following _quarto.yml:
project:
type: book
book:
title: "Demo"
margin-footer: |
[](https://example.com)
<link rel="preload" href="/img/logo-dark.png" as="image">
format:
html:
theme: cosmo
Then run quarto render index.qmd --to html on Windows.
Expected behavior
Quarto should render without error, treating the margin-footer value as inline markdown/HTML content (since it does not exist as a file).
Actual behavior
Render fails with:
ERROR: The filename, directory name, or volume label syntax is incorrect. (os error 123): stat '[](https://example.com)
<link rel="preload" href="/img/logo-dark.png" as="image">
Stack trace points to resolveProjectPaths in websiteProjectConfig.
Root cause
In website-config.ts:
const resolveProjectPaths = (maybePath: string) => {
if (existsSync(maybePath)) {
return join(projectDir, maybePath);
} else {
return maybePath;
}
};
existsSync should be replaced with safeExistsSync (which Quarto already uses elsewhere, e.g. in expandMarkdownFilePath) to gracefully handle invalid paths on Windows.
Workaround
Move the content to a separate file and reference it:
margin-footer: "margin-footer.md"
This works because the string is a valid file path, so existsSync succeeds, and Quarto's expandMarkdownFilePath correctly reads the file content later.
Quarto check output
Quarto 1.9.36
[✓] Checking versions of quarto binary dependencies...
Pandoc version 3.4.0: OK
Dart Sass version 1.80.5: OK
Deno version 2.2.2: OK
Typst version 0.13.0: OK
[✓] Checking versions of quarto dependencies......OK
[✓] Checking Quarto installation......OK
Version: 1.9.36
Path: C:\Users\Andrew\AppData\Local\Programs\Quarto\bin
[✓] Checking tools....................OK
TinyTeX: (not installed)
Chromium: (not installed)
[✓] Checking LaTeX....................OK
[✓] Checking basic markdown render....OK
[✓] Checking R installation...........OK
Version: 4.5.0
Path: C:/PROGRA~1/R/R-45~1.0
LibPaths:
- C:/Program Files/R/R-4.5.0/library
knitr: 1.50
[✓] Checking Knitr engine render......OK
Your environment
- OS: Windows 11
- Quarto: 1.9.36
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.