vitest-dev/vitest · error · Error
Vitest Module Runner doesn't support Vite HMR events.
Error message
Vitest Module Runner doesn't support Vite HMR events.
What it means
ServerModuleRunner is constructed with hmr:false and its transport.invoke (serverRunner.ts:22) only handles 'custom' events; any other Vite HMR event type (full-reload, update, etc.) is rejected. Vitest's runner intentionally doesn't participate in Vite's HMR — it runs modules on demand.
Source
Thrown at packages/vitest/src/node/environments/serverRunner.ts:22
import { readFile } from 'node:fs/promises'
import { isRunnableDevEnvironment } from 'vite'
import { ModuleRunner } from 'vite/module-runner'
import { VitestModuleEvaluator } from '#module-evaluator'
import { normalizeResolvedIdToUrl } from './normalizeUrl'
export class ServerModuleRunner extends ModuleRunner {
constructor(
private environment: DevEnvironment,
fetcher: VitestFetchFunction,
private config: ResolvedConfig,
) {
super(
{
hmr: false,
transport: {
async invoke(event) {
if (event.type !== 'custom') {
throw new Error(`Vitest Module Runner doesn't support Vite HMR events.`)
}
const { name, data } = event.data
if (name === 'getBuiltins') {
return await environment.hot.handleInvoke(event)
}
if (name !== 'fetchModule') {
return { error: new Error(`Unknown method: ${name}. Expected "fetchModule".`) }
}
try {
const result = await fetcher(data[0], data[1], environment, false, data[2])
if ('tmp' in result) {
const code = await readFile(result.tmp)
return { result: { ...result, code } }
}
return { result }
}
catch (error) {
return { error }View on GitHub (pinned to d568f8ce37)
Solutions
- Don't route HMR events through the vitest runner transport — only send 'custom' events if you must use it.
- Disable/skip HMR-emitting plugin logic under vitest (guard on process.env.VITEST or command === 'serve' && !import.meta.env.VITEST).
- Use the regular environment.hot channel for vitest-aware messaging instead of HMR.
Example fix
// before (vite plugin)
server.ws.send({ type: 'full-reload' })
// after
if (!process.env.VITEST) server.ws.send({ type: 'full-reload' }) Defensive patterns
Strategy: validation
Validate before calling
transport: {
async invoke(event) {
if (event.type !== 'custom') return { error: new Error('HMR not supported') }
// ...
}
} Type guard
function isCustomEvent(event: any): boolean {
return event?.type === 'custom'
} Prevention
- Only send 'custom' events through the vitest runner transport.
- Guard HMR-emitting plugin code with process.env.VITEST.
- Use environment.hot for vitest-aware messaging, not Vite HMR.
When it happens
Trigger: A Vite plugin, custom transport, or HMR client pushing a non-custom event (e.g. server.ws.send({ type: 'full-reload' })) into the vitest module-runner transport. Should never occur in standard vitest flows.
Common situations: A custom Vite plugin firing HMR events during vitest runs; a misconfigured environment that wires HMR into the runner transport; experimental plugin development.
Related errors
- Failed to import test file ${filepath}
- Test function is not found. Did you add it using `setFn`?
- Cannot find iframe with id ${event.iframeId}
- Cannot spawn child server without a parent dev server.
- Access denied to "${path}". See Vite config documentation fo
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/815f430ba07f8904.json.
Report an issue: GitHub.