Skip to content

Server function RPCs fail with (0 , __vite_ssr_import_N__.x) is not a function after HMR — partial-exports race with plain named imports (vite 8.1.3) #7825

Description

@alvarogomezj

Which project does this relate to?

Start

Describe the bug

After an HMR invalidation in dev, server function RPC calls (/_serverFn/…) start failing with:

TypeError: (0 , __vite_ssr_import_0__.fetchData) is not a function

where fetchData is a plain named export of an app module (a shared helper imported by several server functions). Once broken, the dev server keeps returning the error until it is restarted.

This looks like the same class of bug as #7285 / #5673, which was closed as fixed by vitejs/vite#22369 (shipped in vite@8.0.12). That fix does resolve the document SSR path — curling the page after an edit renders fine — but the server-function RPC path still races. Notably, #22369 is scoped to re-export chains ("partial-exports race on concurrent imports of in-flight invalidated re-export chains"); here the same race happens with a plain named import, which the fix does not cover. So this likely needs another upstream fix in Vite's module runner, but I'm filing it here first since Start's serverFn RPCs are how it surfaces (and #7285 lived here).

Steps to reproduce

Minimal reproduction (fresh npm install, reproduces reliably):

https://github.com/alvarogomezj/tanstack-start-serverfn-hmr-race

npm install
npm run dev          # terminal 1
npm run reproduce    # terminal 2 — puppeteer opens the page, appends a comment
                     # to a server-fn file, and reports the broken RPC payloads

Or manually: open http://localhost:3100/ (a route whose loader calls 8 server functions in parallel, all of which import a shared helper), then append a comment to src/service1.actions.ts and save. Several of the 8 RPC responses now carry the is not a function error and the page renders ERROR rows. Typically 3–5 of 8 calls fail; the count varies because it's a race.

The setup mirrors a real mid-size app (~20 routes, ~40 server-function modules sharing a fetch-wrapper helper) where this happens on every save of a route/server file. The repro's shared helper uses a 300 ms top-level await to stand in for the evaluation time that a real import subtree takes naturally.

Expected behavior

Server functions keep working after HMR, or the affected environment is fully re-evaluated before serving RPCs.

What seems to happen

Instrumenting the SSR module runner's evaluator (runInlinedModule) shows this order after the edit, with the 8 invalidated ?tss-serverfn-split modules re-evaluating concurrently (one per in-flight RPC):

EVAL-START service1.actions.ts?tss-serverfn-split
EVAL-START service2.actions.ts?tss-serverfn-split
...
EVAL-START helper.ts        <- shared dep starts evaluating (in-flight)
EVAL-START api1.ts
EVAL-END   api1.ts          <- finishes WITHOUT awaiting in-flight helper.ts
EVAL-END   service1.actions.ts?tss-serverfn-split
...
EVAL-END   helper.ts        <- shared dep finishes last

api1.ts completes while its dependency helper.ts is still evaluating, so its imported binding is undefined when the RPC handler runs.

I saw the identical failure shape in the real app for imports from @tanstack/react-start/server too ((0 , __vite_ssr_import_1__.getCookie) is not a function), consistent with the re-export-chain variant of the same race.

For triage, things I ruled out in the real app:

Workaround

A dev-only Vite plugin that restarts the dev server whenever a file in the server-function graph actually changes content (SHA-1 dedupe to ignore editor safe-write saves), then sends a full-reload to clients after warming the new server with a self-fetch (the automatic client reload otherwise races the server warm-up and renders the error into the page). Reliable, but a full restart per server-file edit is a heavy price, and pure Fast Refresh flows lose out.

Platform

  • OS: macOS (Darwin 25.5.0)
  • Node: 24.14.1
  • Browser: Chrome (also headless via puppeteer in the repro script)

Package versions

Package Version
@tanstack/react-start 1.168.27
@tanstack/react-router 1.170.17
vite 8.1.3
@vitejs/plugin-react 6.0.3
react / react-dom 19.2.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    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