Skip to content

[Start] virtual:tanstack-start-client-entry 404 in pnpm monorepo #6588

@erquhart

Description

@erquhart

Which project does this relate to?

Start

Describe the bug

When running TanStack Start in a pnpm monorepo (Rush in this case), the client fails to hydrate with a 404 error for the virtual client entry module:

GET http://localhost:3000/@id/virtual:tanstack-start-client-entry net::ERR_ABORTED 404 (Not Found)
Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: http://localhost:3000/@id/virtual:tanstack-start-client-entry

The SSR renders correctly, but client-side hydration completely fails.

Root Cause Analysis

The tanstackStart() plugin calculates the default client entry path relative to its own location:

const defaultEntryDir = path.resolve(currentDir, "..", "..", "plugin", "default-entry")

In a pnpm monorepo, the package is symlinked to the pnpm store:

node_modules/@tanstack/react-start -> ../../../../common/temp/node_modules/.pnpm/@tanstack+react-start@1.135.2_.../

The plugin sets up a Vite alias from virtual:tanstack-start-client-entry to this symlinked path. However, when the browser requests /@id/virtual:tanstack-start-client-entry, Vite's module server doesn't intercept the request - it falls through to TanStack Start's catch-all router middleware, which returns a 404 HTML page.

Workaround

Creating a local src/client.tsx file bypasses the default entry resolution:

import { StrictMode, startTransition } from 'react'
import { hydrateRoot } from 'react-dom/client'
import { StartClient } from '@tanstack/react-start/client'

startTransition(() => {
  hydrateRoot(
    document,
    <StrictMode>
      <StartClient />
    </StrictMode>,
  )
})

This works because the plugin then uses the local file instead of resolving to the pnpm store path.

Your Example Website or App

This occurs in a Rush monorepo with pnpm. A similar issue was reported by an NX monorepo user: https://www.answeroverflow.com/m/1446212939764990075

Steps to Reproduce the Bug or Issue

  1. Create a TanStack Start app inside a pnpm monorepo (Rush, Turborepo, or plain pnpm workspaces)
  2. Run vite dev
  3. Open browser - SSR works but console shows the 404 error
  4. Any client-side interactivity fails

Expected behavior

The virtual client entry module should be served correctly by Vite regardless of whether the package is symlinked.

Screenshots or Videos

No response

Platform

  • Start Version: 1.135.2
  • Vite Version: 7.2.2
  • OS: macOS
  • Package Manager: pnpm (Rush monorepo)

Additional context

The official start-workos example does not include a src/client.tsx, confirming this file should not be required. The issue appears to be in how Vite 7's Environment API handles aliases pointing to symlinked paths in the pnpm store.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions