Description
Since @tanstack/react-start@1.167.17 (PR #7144), the dev server breaks when accessed through a reverse proxy (Cloudflare, nginx, Caddy, Pangolin). The browser receives 400 Bad Request for the new #tanstack-start-plugin-adapters virtual module.
Reproduction
- Set up a TanStack Start app with
@tanstack/react-start@1.167.17+
- Access the dev server through any reverse proxy (e.g., Cloudflare Tunnel, nginx, Caddy)
- The app fails to load
Works: Direct access via localhost:3000
Breaks: Access through reverse proxy → https://myapp.example.com
Browser console errors
GET https://myapp.example.com/@id/__x00__%23tanstack-start-plugin-adapters net::ERR_ABORTED 400 (Bad Request)
Uncaught (in promise) TypeError: Failed to fetch dynamically imported module:
https://myapp.example.com/@id/virtual:tanstack-start-client-entry
Root Cause
PR #7144 introduced a new virtual module #tanstack-start-plugin-adapters in packages/start-plugin-core/src/vite/serialization-adapters-plugin.ts. This module is:
- Resolved via
resolveId/load hooks (producing a \0-prefixed ID)
- Imported by client-side code in
hydrateStart.ts
Vite encodes the \0 prefix as __x00__ in browser-facing URLs, resulting in:
/@id/__x00__%23tanstack-start-plugin-adapters
Reverse proxies and WAFs (Cloudflare, nginx, Caddy) correctly reject URLs containing null-byte representations as a security measure (HTTP anomaly detection).
Why other virtual modules work
The existing virtual modules (#tanstack-start-entry, #tanstack-router-entry) use resolve.alias in the Vite config, mapping to real filesystem paths. They never become \0-prefixed, so no /@id/__x00__ URL appears in the browser.
#tanstack-start-server-fn-resolver does use resolveId/load, but it's only loaded server-side (SSR), never requested by the browser.
#tanstack-start-plugin-adapters is the first virtual module that uses resolveId/load AND is imported by client-side code.
Suggested Fix
Handle #tanstack-start-plugin-adapters the same way as #tanstack-start-entry — via resolve.alias pointing to a real file (e.g., packages/start-client-core/src/fake-entries/plugin-adapters.ts), instead of the resolveId/load virtual module pattern.
Environment
@tanstack/react-start: 1.167.28 (broken), 1.167.16 (last working)
- Vite: 7.3.2
- Reverse proxy: Pangolin (Caddy-based) + Cloudflare DNS proxy
- OS: Windows 11 (dev), Linux (proxy)
- Browser: Chrome
Workaround
Pin @tanstack/react-start to 1.167.16 and @tanstack/react-router to 1.168.10.
Description
Since
@tanstack/react-start@1.167.17(PR #7144), the dev server breaks when accessed through a reverse proxy (Cloudflare, nginx, Caddy, Pangolin). The browser receives 400 Bad Request for the new#tanstack-start-plugin-adaptersvirtual module.Reproduction
@tanstack/react-start@1.167.17+Works: Direct access via
localhost:3000Breaks: Access through reverse proxy →
https://myapp.example.comBrowser console errors
Root Cause
PR #7144 introduced a new virtual module
#tanstack-start-plugin-adaptersinpackages/start-plugin-core/src/vite/serialization-adapters-plugin.ts. This module is:resolveId/loadhooks (producing a\0-prefixed ID)hydrateStart.tsVite encodes the
\0prefix as__x00__in browser-facing URLs, resulting in:Reverse proxies and WAFs (Cloudflare, nginx, Caddy) correctly reject URLs containing null-byte representations as a security measure (HTTP anomaly detection).
Why other virtual modules work
The existing virtual modules (
#tanstack-start-entry,#tanstack-router-entry) useresolve.aliasin the Vite config, mapping to real filesystem paths. They never become\0-prefixed, so no/@id/__x00__URL appears in the browser.#tanstack-start-server-fn-resolverdoes useresolveId/load, but it's only loaded server-side (SSR), never requested by the browser.#tanstack-start-plugin-adaptersis the first virtual module that usesresolveId/loadAND is imported by client-side code.Suggested Fix
Handle
#tanstack-start-plugin-adaptersthe same way as#tanstack-start-entry— viaresolve.aliaspointing to a real file (e.g.,packages/start-client-core/src/fake-entries/plugin-adapters.ts), instead of theresolveId/loadvirtual module pattern.Environment
@tanstack/react-start: 1.167.28 (broken), 1.167.16 (last working)Workaround
Pin
@tanstack/react-startto1.167.16and@tanstack/react-routerto1.168.10.