quarto-dev / quarto-dev/quarto-cli
quarto preview of a document outside website output-dir publishes Browse at .../../file.html and 404s
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 6k
- Forks
- 458
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 41
Description
I have:
- searched the issue tracker for similar issues
- installed the latest version of Quarto CLI
- formatted my issue following the Bug Reports guide
Bug description
Bug description
In a website project with output-dir, previewing a document that is not written into that output directory still uses the website preview server (rooted at output-dir). The browse URL becomes something like:
Browse at http://localhost:PORT/../_draft.html
The browser/IDE normalizes that to /_draft.html, which is not served from output-dir, so the preview pane gets 404. The HTML file itself is rendered successfully next to the source.
This looks related to the #13804 / #14298 / #14300 preview-path work: #14300 fixed the single-file (isSingleFile) case, but not the case where a real website project renders a file outside projectOutputDir.
Steps to reproduce
Steps to reproduce
mkdir -p repro && cd repro
cat > _quarto.yml <<'EOF'
project:
type: website
output-dir: _output
render:
- index.qmd
EOF
cat > index.qmd <<'EOF'
---
title: Site
---
Hello site
EOF
cat > _draft.qmd <<'EOF'
---
title: Draft
format: html
---
Hello draft
EOF
# Build the site once so _output/ exists
quarto render
# Preview the draft (not in render list; HTML lands next to source)
quarto preview _draft.qmd --no-browser --no-watch-inputs --port 5678
Observe:
Output created: _draft.html
Browse at http://localhost:5678/../_draft.html
Then:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5678/ # 200 (index)
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5678/_draft.html # 404
ls _draft.html _output/_draft.html
# _draft.html exists; _output/_draft.html does not
Same failure happens for a non-underscore file that is also omitted from project.render (so output is still written beside the source, not into _output).
Actual behavior
- Browse URL includes
../filename.html - Preview server is still
projectHtmlFileRequestHandlerrooted at_output - Requested path 404s
- VS Code / Cursor Quarto preview is unusable for these docs even though render succeeded
Suggested fix direction
In previewInitialPath() / handler selection in src/command/preview/preview.ts, when
relative(projectOutputDir(project), outputFile)
escapes the output dir (starts with ..), treat it like single-file preview (htmlFileRequestHandler + empty initial path) instead of the website handler.
Expected behavior
Preview should serve the rendered document successfully. For outputs outside projectOutputDir, it should fall back to the single-file handler / root URL behavior (as #14300 did for isSingleFile), e.g.:
Browse at http://localhost:PORT/GET /→ 200 with the draft HTML
Workarounds
quarto render draft.qmdand open the.htmldirectly- Temporarily move/rename
_quarto.ymlso preview runs in single-file mode - Add the file to the website
render:list so output lands underoutput-dir
Your environment
- IDE: Cursor / VS Code Quarto preview (
quarto preview … --no-browser --no-watch-inputs) - OS: macOS (darwin 25)
Quarto check output
Quarto 1.10.18
[✓] Checking versions of quarto binary dependencies...
Pandoc version 3.10.0: OK
Dart Sass version 1.101.0: OK
Deno version 2.7.14: OK
Typst version 0.15.1: OK
[✓] Checking Quarto installation......OK
Version: 1.10.18
Path: /Applications/quarto/bin
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.
Research direction
Start in src/command/preview/preview.ts, focusing on previewInitialPath() and the handler-selection logic. Run the supplied website project reproduction with an omitted document, then trace how a path outside projectOutputDir is handled. Done means the draft is served successfully at the root URL instead of producing a ../ URL and a 404.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100