cloudflare / cloudflare/vinext

Windows: production server 404s every nested static asset - StaticFileCache keys built with backslashes

Open Beginner friendly
#2,696 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
8.8k
Forks
406
Avg merge
2d 6h
Merged PRs (30d)
120

Description

# Upstream issue draft — for Rob's word before filing (external publish)

Target: vinext repository (npm package `vinext`; repo URL per its package.json/npm page)
Verified present in: 0.0.50 and 1.0.0-beta.3 (latest at time of writing, 2026-07-24)

---

**Title:** Windows: production server 404s every nested static asset — StaticFileCache keys built with backslashes

**Body:**

On Windows, `vinext start` (production server) returns the router's NOT_FOUND for every static file in a subdirectory of `dist/client/` — including all hashed `/assets/*` JS/CSS — while SSR routes work fine. The page loads as unstyled HTML with a failed dynamic import.

**Cause:** `src/server/static-file-cache.ts` (`walkFilesWithStats`) yields `relativePath: path.relative(base, file)`. On Windows `path.relative` returns backslash-separated paths, so cache keys become `/assets\index-XXXX.js` while request lookups use URL pathnames (`/assets/index-XXXX.js`). Every nested file misses. Because a provided `StaticFileCache` has no filesystem fallback in `tryServeStatic` (a miss returns `false` immediately), the request falls through to routing and 404s. The `.vite/` exclusion and `assets/`-prefix immutable-caching checks silently misbehave for the same reason (`startsWith("assets/")` never matches `assets\...`).

**Repro (Windows):**
```
npx vinext build
npx vinext start --port 3000
# open the site: every /assets/* request → 404 JSON {"state":"NOT_FOUND"}
```

**Fix (one line):**
```diff
- relativePath: path.relative(base, batch[j]),
+ relativePath: path.relative(base, batch[j]).split(path.sep).join("/"),
```
Verified locally on Windows 11 / Node 24: all nested lookups resolve, `.vite/` exclusion and hashed-asset cache headers behave correctly, page loads with zero console errors.

Present in 0.0.50 through 1.0.0-beta.3 (the beta's `walkFilesWithStats` is identical in this respect).

---

BOUNDARY: NOT FILED. Filing is an external publish under RIG001 law — Rob's word required. On word: file via gh or web, record issue URL on the rail.

Contributor guide

Open the contributing guide

Research direction

Start in src/server/static-file-cache.ts at walkFilesWithStats and trace how its relativePath values reach tryServeStatic. Reproduce with npx vinext build and npx vinext start on Windows; done means nested /assets/* requests resolve, .vite/ is excluded, and hashed assets receive the expected cache behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.