[Start] virtual:tanstack-start-client-entry 404 in pnpm monorepo (regression on react-start@1.168 + vite@8)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 15.1k
- Forks
- 1.9k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 143
Description
Which project does this relate to?
Start
Bug
On a fresh install with @tanstack/react-start@1.168.0 + vite@8.0.13 in a pnpm monorepo (enableGlobalVirtualStore: true), every dev request to:
GET /@id/virtual:tanstack-start-client-entry
returns 404. Hydration fails (Uncaught (in promise) TypeError: Failed to fetch dynamically imported module) and the routed <Outlet /> renders empty — header and footer from the pathless layout show, the page body is blank.
This is the exact symptom of #6588 (closed, "fixed in v1.159.6" via #7178), so I'm filing this as a regression rather than commenting on the closed thread.
Repro
- pnpm 11.x, Node 24.x, macOS
vite@8.0.13@tanstack/react-start@1.168.0→ resolvesstart-plugin-core@1.170.0,start-server-core@1.168.0,start-client-core@1.169.0pnpm-workspace.yaml:enableGlobalVirtualStore: true- Start the Vite dev server, open
/in any browser
SSR HTML emits:
import("/@id/virtual:tanstack-start-client-entry")
Diagnosis
In Vite 8 the /@id/ middleware requires virtual-module URLs to carry the null-byte prefix encoded as __x00__ (or %00):
| URL | Status |
|---|---|
/@id/virtual:tanstack-start-client-entry |
404 |
/@id/__x00__virtual:tanstack-start-client-entry |
200 |
/@id/%00virtual:tanstack-start-client-entry |
200 |
start-plugin-core@1.170.0's createVirtualModule correctly returns the \0-prefixed resolvedId from its resolveId hook, but the SSR-emitted client bootstrap (from start-server-core@1.168.0) writes the bare-prefix URL into the HTML, so Vite 8's URL-to-id middleware never reaches the plugin's hook.
Workaround
Inline Vite plugin that rewrites the URL before resolution (works locally):
import { defineConfig, type Plugin } from 'vite'
const tanstackVirtualUrlShim = (): Plugin => ({
name: 'tanstack-start:virtual-url-shim',
enforce: 'pre',
configureServer(server) {
server.middlewares.use((req, _res, next) => {
if (req.url?.startsWith('/@id/virtual:tanstack-')) {
req.url = req.url.replace('/@id/virtual:', '/@id/__x00__virtual:')
}
next()
})
},
})
export default defineConfig({
plugins: [tanstackVirtualUrlShim(), /* ...rest */],
})
Related
- Closed: #6588 (original report)
- Closed: #7155 (reverse-proxy variant — same
\0-prefix discussion) - Merged: #7178 (the previous fix this regressed against)
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
Reproduce the failure in a fresh pnpm monorepo with Vite 8, then start in the start-server-core SSR client bootstrap and trace the virtual module URL it emits. Compare that URL with createVirtualModule and its resolveId hook in start-plugin-core. Done means the client entry resolves under Vite 8, hydration succeeds, and the routed page renders without the 404.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript, vite
- Domain
- build-system, full-stack
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100