diff --git a/.github/workflows/test-smokes.yml b/.github/workflows/test-smokes.yml
index bbde6d158ad..b50359571df 100644
--- a/.github/workflows/test-smokes.yml
+++ b/.github/workflows/test-smokes.yml
@@ -139,6 +139,13 @@ jobs:
sudo apt-get install -y libharfbuzz-dev libfribidi-dev
sudo apt-get install -y poppler-utils
+ - name: Install rsvg-convert for SVG conversion tests
+ # Only do it on linux runner, and only if we are running the relevant tests
+ if: runner.os == 'Linux' && contains(inputs.buckets, 'render-pdf-svg-conversion')
+ run: |
+ sudo apt-get update -y
+ sudo apt-get install -y librsvg2-bin
+
- name: Restore R packages
working-directory: tests
run: |
diff --git a/news/changelog-1.9.md b/news/changelog-1.9.md
index be96d684a8c..da6de3c010c 100644
--- a/news/changelog-1.9.md
+++ b/news/changelog-1.9.md
@@ -41,6 +41,7 @@ All changes included in 1.9:
### `pdf`
- ([#10291](https://github.com/quarto-dev/quarto-cli/issues/10291)): Fix detection of babel hyphenation warnings with straight-quote format instead of backtick-quote format.
+- ([#13661](https://github.com/quarto-dev/quarto-cli/issues/13661)): Fix LaTeX compilation errors when using `mermaid-format: svg` with PDF/LaTeX output. SVG diagrams are now written directly without HTML script tags. Note: `mermaid-format: png` is recommended for best compatibility. SVG format requires `rsvg-convert` (or Inkscape with `use-rsvg-convert: false`) in PATH for conversion to PDF, and may experience text clipping in diagrams with multi-line labels.
- ([rstudio/tinytex-releases#49](https://github.com/rstudio/tinytex-releases/issues/49)): Fix detection of LuaTeX-ja missing file errors by matching both "File" and "file" in error messages.
## Projects
diff --git a/src/core/handlers/mermaid.ts b/src/core/handlers/mermaid.ts
index edb5484bc0d..8bef0cd1846 100644
--- a/src/core/handlers/mermaid.ts
+++ b/src/core/handlers/mermaid.ts
@@ -39,7 +39,7 @@ import { convertFromYaml } from "../lib/yaml-schema/from-yaml.ts";
import { readYamlFromString } from "../yaml.ts";
import { pandocHtmlBlock, pandocRawStr } from "../pandoc/codegen.ts";
import { LocalizedError } from "../lib/located-error.ts";
-import { warning } from "../../deno_ral/log.ts";
+import { info, warning } from "../../deno_ral/log.ts";
import { FormatDependency } from "../../config/types.ts";
import { mappedDiff } from "../mapped-text.ts";
import { escape } from "../../core/lodash.ts";
@@ -228,7 +228,7 @@ mermaid.initialize(${JSON.stringify(mermaidOpts)});
?.[kFigResponsive];
const makeSvg = async () => {
- setupMermaidSvgJsRuntime();
+ // Extract and process SVG
let svg = asMappedString(
(await handlerContext.extractHtml({
html: content,
@@ -306,7 +306,29 @@ mermaid.initialize(${JSON.stringify(mermaidOpts)});
svg = mappedDiff(svg, oldSvgSrc);
}
- if (isMarkdownOutput(handlerContext.options.format, ["gfm"])) {
+ // For formats that don't support JavaScript runtime (LaTeX/PDF, DOCX, Typst, etc.),
+ // write SVG file directly without postprocess script. This avoids LaTeX compilation
+ // errors from HTML script tags but may result in text clipping in diagrams with
+ // multi-line labels (see https://github.com/quarto-dev/quarto-cli/issues/1622).
+ if (
+ isMarkdownOutput(handlerContext.options.format, ["gfm"]) ||
+ !isJavascriptCompatible(handlerContext.options.format)
+ ) {
+ // Emit info message for non-JS formats (excluding GFM which doesn't have the issue)
+ if (!isMarkdownOutput(handlerContext.options.format, ["gfm"])) {
+ let warning = `Using mermaid-format: svg with ${
+ handlerContext.options.format.pandoc.to ?? "non-HTML"
+ } format. Note: diagrams with multi-line text labels may experience clipping`;
+
+ // LaTeX-based formats also require external tooling
+ if (isLatexOutput(handlerContext.options.format.pandoc)) {
+ warning += " and requires external tooling (rsvg-convert or Inkscape)";
+ }
+
+ warning += ". Consider using mermaid-format: png if issues occur.";
+
+ info(warning);
+ }
const { sourceName, fullName } = handlerContext
.uniqueFigureName(
"mermaid-figure-",
@@ -323,6 +345,8 @@ mermaid.initialize(${JSON.stringify(mermaidOpts)});
makeFigLink(sourceName, widthInInches, heightInInches, true),
);
} else {
+ // For JavaScript-compatible formats, use runtime postprocessing
+ setupMermaidSvgJsRuntime();
return this.build(
handlerContext,
cell,
diff --git a/src/resources/filters/quarto-post/pdf-images.lua b/src/resources/filters/quarto-post/pdf-images.lua
index fc21e3e0026..daf8a3e5fa7 100644
--- a/src/resources/filters/quarto-post/pdf-images.lua
+++ b/src/resources/filters/quarto-post/pdf-images.lua
@@ -36,7 +36,8 @@ local function convert_svg(image)
local stem = pandoc.path.split_extension(image.src)
local output = stem .. '.pdf'
if not _quarto.file.exists(output) then
- warn("Skipping SVG conversion for " .. path .. " because use-rsvg-convert is false, but required PDF file does not exist: " .. output)
+ warn("Skipping SVG conversion for " .. image.src .. " because use-rsvg-convert is false, but required PDF file does not exist: " .. output)
+ return nil
else
image.src = output
return image
diff --git a/tests/README.md b/tests/README.md
index 5a6c200169f..99677e6d7b5 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -120,6 +120,30 @@ $env:QUARTO_TESTS_NO_CONFIG=$true
`docs/smoke-all/` is a specific folder to run some tests written directly within `.qmd`, `.md` or `.ipynb` files (but files starting with `_` will be ignored). They are run through the `smoke/smoke-all.tests.ts` script. To ease running smoke-all tests, `run-tests.sh` has a special behavior where it will run `./smoke/smoke-all.tests.ts` when passed a `.qmd`, `.md` or `.ipynb` file, not starting with `_`.
+##### Controlling test execution with metadata
+
+Smoke-all tests support metadata in the `_quarto` key to control when tests are run:
+
+**Skip tests on CI:**
+
+```yaml
+_quarto:
+ tests-on-ci: false
+```
+
+**Skip tests on specific operating systems:**
+
+```yaml
+_quarto:
+ skip-on-os: linux # Skip only on Linux
+ skip-on-os: [linux, darwin] # Skip on Linux and macOS
+ skip-on-os: windows # Skip only on Windows
+```
+
+Valid OS values are: `linux`, `darwin` (macOS), `windows`
+
+This is useful when tests require platform-specific dependencies or have known platform-specific issues that need separate investigation.
+
```bash
# run tests for all documents in docs/smoke-all/
./run-tests.sh smoke/smoke-all.tests.ts
diff --git a/tests/docs/manual/mermaid-svg-pdf-tooling.qmd b/tests/docs/manual/mermaid-svg-pdf-tooling.qmd
new file mode 100644
index 00000000000..593b364ac38
--- /dev/null
+++ b/tests/docs/manual/mermaid-svg-pdf-tooling.qmd
@@ -0,0 +1,129 @@
+---
+title: "Manual Test: Mermaid SVG with PDF - External Tooling"
+format:
+ pdf:
+ mermaid-format: svg
+ keep-tex: true
+---
+
+## Purpose
+
+This document is for **manual testing** of mermaid-format:svg with PDF output,
+specifically to verify behavior with different external tooling configurations.
+
+**Why manual?** Automated CI tests cannot easily verify:
+- Actual PDF generation with rsvg-convert
+- Inkscape fallback behavior
+- Platform-specific tooling issues (especially Windows)
+- Full conversion pipeline end-to-end
+
+## Simple Diagram
+
+```{mermaid}
+graph TD
+ A[Start] --> B{Decision}
+ B -->|Yes| C[Good]
+ B -->|No| D[Bad]
+ C --> E[End]
+ D --> E
+```
+
+## Multi-line Labels (Clipping Test)
+
+This tests potential text clipping issues with multi-line labels:
+
+```{mermaid}
+graph TD
+ A["Line 1
Line 2
Line 3"] --> B["Another
Multi
Line
Label"]
+ B --> C["Final
Node"]
+```
+
+## Manual Testing Checklist
+
+### Test 1: With rsvg-convert (Default)
+- [ ] Ensure `rsvg-convert` is on PATH
+- [ ] Run: `quarto render mermaid-svg-pdf-tooling.qmd`
+- [ ] Verify: INFO message includes "requires external tooling"
+- [ ] Verify: PDF generates successfully
+- [ ] Check `.tex` file for `\includesvg` commands
+- [ ] Verify: No script tags in LaTeX output
+- [ ] Open PDF: Diagrams render correctly
+
+### Test 2: Without rsvg-convert
+- [ ] Remove rsvg-convert from PATH or rename binary temporarily
+- [ ] Run: `quarto render mermaid-svg-pdf-tooling.qmd`
+- [ ] Verify: INFO message about tooling requirement
+- [ ] Verify: Error about missing rsvg-convert
+- [ ] Expected behavior: Render fails with clear error
+
+### Test 3: Inkscape Fallback (use-rsvg-convert: false)
+Create variant document with:
+```yaml
+format:
+ pdf:
+ mermaid-format: svg
+ use-rsvg-convert: false
+ pdf-engine-opt: ["-shell-escape"]
+ keep-tex: true
+```
+
+- [ ] Ensure Inkscape is installed
+- [ ] Run render with above config
+- [ ] Verify: INFO message about tooling
+- [ ] Verify: PDF generates via Inkscape (check logs)
+- [ ] Check `.tex` file: uses `\includesvg` with Inkscape
+- [ ] Open PDF: Diagrams render correctly
+
+### Test 4: Windows-Specific
+- [ ] Test on Windows with rsvg-convert (if available via Scoop/other)
+- [ ] Test on Windows without rsvg-convert
+- [ ] Test Inkscape fallback on Windows
+- [ ] Document any Windows-specific issues
+
+### Test 5: Comparison with PNG (Control)
+Create variant with `mermaid-format: png`:
+
+- [ ] Run: `quarto render` with png format
+- [ ] Verify: NO warning about external tooling
+- [ ] Verify: PDF generates successfully
+- [ ] Quality comparison: SVG vs PNG in final PDF
+
+## Expected Results Summary
+
+| Scenario | Warning | PDF Generation | Notes |
+|----------|---------|----------------|-------|
+| rsvg-convert available | ✅ Yes | ✅ Success | Default path |
+| No rsvg-convert | ✅ Yes | ❌ Error | Clear error message |
+| Inkscape + shell-escape | ✅ Yes | ✅ Success | Fallback works |
+| PNG format | ❌ No | ✅ Success | No tooling needed |
+
+## Platform-Specific Notes
+
+### Linux/Mac
+- rsvg-convert typically available via package managers
+- `librsvg` package usually includes rsvg-convert
+- Inkscape widely available
+
+### Windows
+- rsvg-convert NOT easily available (complex setup)
+- Can use Scoop: `scoop install rsvg-convert` (if r-bucket configured)
+- Inkscape available but requires shell-escape configuration
+- Most users should prefer PNG format on Windows
+
+## Recording Results
+
+After completing manual tests, document results in the beads issue notes field
+for quarto-cli-idi. Include:
+
+- Platforms tested (OS, versions)
+- Which scenarios passed/failed
+- Any unexpected behavior
+- Screenshots if helpful
+- Recommendations for users
+
+## See Also
+
+- Automated test: `tests/docs/smoke-all/2025/11/10/13661.qmd`
+- DOCX test: `tests/docs/smoke-all/2025/11/14/mermaid-svg-docx.qmd`
+- Beads issue: quarto-cli-idi
+- GitHub issue: #13661
diff --git a/tests/docs/smoke-all/2024/01/26/issue-8299-1.qmd b/tests/docs/smoke-all/2024/01/26/issue-8299-1.qmd
deleted file mode 100644
index b4227a1458b..00000000000
--- a/tests/docs/smoke-all/2024/01/26/issue-8299-1.qmd
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: issue-8299
-format: pdf
-_quarto:
- tests:
- pdf:
- fileExists:
- outputPath: simple-svg.pdf
----
-
-
\ No newline at end of file
diff --git a/tests/docs/smoke-all/2024/01/26/issue-8299-2.qmd b/tests/docs/smoke-all/2024/01/26/issue-8299-2.qmd
deleted file mode 100644
index d2b57dd2f3f..00000000000
--- a/tests/docs/smoke-all/2024/01/26/issue-8299-2.qmd
+++ /dev/null
@@ -1,12 +0,0 @@
----
-title: issue-8299-2
-format: latex
-use-rsvg-convert: false
-_quarto:
- tests:
- latex:
- ensureFileRegexMatches:
- - ["simple-svg.pdf"]
----
-
-
\ No newline at end of file
diff --git a/tests/docs/smoke-all/2025/11/10/13661.qmd b/tests/docs/smoke-all/2025/11/10/13661.qmd
new file mode 100644
index 00000000000..6068bfb2359
--- /dev/null
+++ b/tests/docs/smoke-all/2025/11/10/13661.qmd
@@ -0,0 +1,41 @@
+---
+title: "Mermaid SVG format with LaTeX - No script tags (#13661)"
+# Test strategy: Use format:latex with use-rsvg-convert:false to:
+# - Test mermaid-format:svg (the actual bug scenario)
+# - Generate .tex file without compiling PDF (avoids needing rsvg-convert/Inkscape in CI)
+# - Verify warning message about clipping + external tooling
+# - Verify LaTeX uses \includesvg (not \includegraphics)
+# - Verify NO HTML