docusaurus serve: static assets 404 when baseUrl is not "/" and trailingSlash is true
Maintainers usually reply within 1 day
@Shashank01729 is already working on this.
Since Sep 23, 2026.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 75/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- node.js, typescript
Research direction
The issue is in packages/docusaurus/src/commands/serve.ts, where the regex for asset detection is too restrictive. Start by examining the serve command's logic, particularly the looksLikeAsset check. Use the provided reproduction steps to verify the bug. The fix involves splitting the URL to isolate the pathname before checking the extension, similar to how applyTrailingSlash works. Test by building and serving a site with the described configuration, then verifying static assets with long extensions and query strings are served correctly.
Written by the indexing model from the issue text.
Description
Have you read the Contributing Guidelines on issues?
- I have read the Contributing Guidelines on issues.
Prerequisites
- I'm using the latest version of Docusaurus.
- I have tried the
npm run clearoryarn clearcommand. - I have tried
rm -rf node_modules yarn.lock package-lock.jsonand re-installing packages. - I have tried creating a repro with https://new.docusaurus.io.
- I have read the console error message carefully (if applicable).
Description
With a non-root baseUrl and trailingSlash: true, docusaurus serve returns 404 for two kinds of static assets:
- extensions longer than 4 characters —
.woff2,.webmanifest,.geojson - any asset requested with a query string —
/img/logo.png?v=1
Both get a 302 to a trailing-slash URL and end up on the 404 page. Web fonts are the most visible casualty, since .woff2 is the standard format.
It comes from the asset check in packages/docusaurus/src/commands/serve.ts:
const looksLikeAsset = !!req.url.match(/\.[a-zA-Z\d]{1,4}$/);
{1,4} is too short for .woff2, and the $ is matched against the raw req.url, so a ?query also prevents the match. applyTrailingSlash(), called right after it, does split the query off first:
// The trailing slash should be handled before the ?search#hash !
const [pathname] = path.split(/[#?]/) as [string, ...string[]];
The asset check just misses that step.
Reproducible demo
No repo needed — the steps below start from a fresh create-docusaurus install and reproduce it in about a minute.
Steps to reproduce
npx create-docusaurus@latest repro-serve classic --javascript && cd repro-serve && npm install- In
docusaurus.config.js, setbaseUrl: '/mysite/'andtrailingSlash: true - Add three static files:
printf 'FAKEWOFF2' > static/custom-font.woff2 printf '{"name":"x"}' > static/site.webmanifest printf 'FAKEPNG' > static/logo-test.png npm run build && npm run serve -- --port 3030- Request them:
curl -sI "http://localhost:3030/mysite/logo-test.png" curl -sI "http://localhost:3030/mysite/logo-test.png?v=1" curl -sI "http://localhost:3030/mysite/custom-font.woff2" curl -sI "http://localhost:3030/mysite/site.webmanifest"
Expected behavior
All four serve the file with status 200 and the correct content type. The trailing slash should only be applied to page URLs, whatever the extension length is and whether or not there is a query string.
Actual behavior
Only the plain .png is served:
/mysite/logo-test.png -> 200 image/png
/mysite/logo-test.png?v=1 -> 302 .../logo-test.png/?v=1 -> 404 text/html
/mysite/custom-font.woff2 -> 302 .../custom-font.woff2/ -> 404 text/html
/mysite/site.webmanifest -> 302 .../site.webmanifest/ -> 404 text/html
Following the redirect returns the HTML 404 page instead of the file:
$ curl -sIL "http://localhost:3030/mysite/custom-font.woff2" | grep -E "^HTTP|^Content-Type"
HTTP/1.1 302 Found
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
Same behavior on main (4.0.0), where the regex is /\.[a-z\d]{1,4}$/i.
Splitting off the query/hash and checking the extension of the pathname fixes all three cases while leaving page redirects untouched:
const [pathname] = req.url.split(/[#?]/) as [string, ...string[]];
const looksLikeAsset = !!path.extname(pathname);
With that change, in the same repro, the three failing URLs return 200 and /mysite/docs/intro still redirects to /mysite/docs/intro/.
Your environment
- Public source code: N/A — repro steps above, from a fresh
create-docusaurussite - Public site URL: N/A — local
docusaurus serve - Docusaurus version used: 3.10.2, also reproduced on
main(4.0.0) - Environment name and version: Node.js v24.21.0
- Operating system and version: macOS 15
Self-service
- I'd be willing to fix this bug myself.
- Dominant language
- TypeScript
- Stars
- 66.5k
- Forks
- 10.1k
- Avg merge
- 23h 6m
- Merged PRs (30d)
- 159
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing 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.
More from facebook/docusaurus
-
Add the mobile-web-app-capable meta tag to the website's PWA configurationPossibly taken @anishagrawal25 claimed this today. Openbug status: needs triage
Difficulty 1/5 Under an hour Newbie friendliness 88/100
facebook/docusaurus#12743 ·
Maintainers usually reply within 1 day
-
Playground cards have inconsistent heightsPossibly taken A pull request linked to this issue is open or already merged. Openbug status: needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
facebook/docusaurus#12739 · 1 comment ·
Maintainers usually reply within 1 day
-
Page title drops a trailing # from the heading, e.g. # Learn C# becomes "Learn C" (AI-assisted)Possibly taken @lx3133584 claimed this 7 days ago. Openbug status: needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
facebook/docusaurus#12644 · 1 comment ·
Maintainers usually reply within 1 day
-
Firefox clips descenders in documentation sidebar labels on WindowsPossibly taken @xusnitdinov claimed this 95 days ago. Openbug status: needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
facebook/docusaurus#12299 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 1/5 1-3 hours Newbie friendliness 72/100
facebook/docusaurus#10490 · 10 comments · 5 reactions ·
Maintainers usually reply within 1 day
All issues in facebook/docusaurus
Similar issues
-
check:passed streams:edit
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
area:mcp bug has repro platform:vscode regression
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
anthropics/claude-code#103970 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day
-
sdk-typescript: unquoted COPY globs in shell form are silently dropped from the image build contextOpenbug javascript
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day