{"id":"815f430ba07f8904","repo":"vitest-dev/vitest","slug":"vitest-module-runner-doesn-t-support-vite-hmr-even","errorCode":null,"errorMessage":"Vitest Module Runner doesn't support Vite HMR events.","messagePattern":"Vitest Module Runner doesn't support Vite HMR events\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/environments/serverRunner.ts","lineNumber":22,"sourceCode":"import { readFile } from 'node:fs/promises'\nimport { isRunnableDevEnvironment } from 'vite'\nimport { ModuleRunner } from 'vite/module-runner'\nimport { VitestModuleEvaluator } from '#module-evaluator'\nimport { normalizeResolvedIdToUrl } from './normalizeUrl'\n\nexport class ServerModuleRunner extends ModuleRunner {\n  constructor(\n    private environment: DevEnvironment,\n    fetcher: VitestFetchFunction,\n    private config: ResolvedConfig,\n  ) {\n    super(\n      {\n        hmr: false,\n        transport: {\n          async invoke(event) {\n            if (event.type !== 'custom') {\n              throw new Error(`Vitest Module Runner doesn't support Vite HMR events.`)\n            }\n            const { name, data } = event.data\n            if (name === 'getBuiltins') {\n              return await environment.hot.handleInvoke(event)\n            }\n            if (name !== 'fetchModule') {\n              return { error: new Error(`Unknown method: ${name}. Expected \"fetchModule\".`) }\n            }\n            try {\n              const result = await fetcher(data[0], data[1], environment, false, data[2])\n              if ('tmp' in result) {\n                const code = await readFile(result.tmp)\n                return { result: { ...result, code } }\n              }\n              return { result }\n            }\n            catch (error) {\n              return { error }","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/node/environments/serverRunner.ts#L4-L40","documentation":"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.","triggerScenarios":"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.","commonSituations":"A custom Vite plugin firing HMR events during vitest runs; a misconfigured environment that wires HMR into the runner transport; experimental plugin development.","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."],"exampleFix":"// before (vite plugin)\nserver.ws.send({ type: 'full-reload' })\n\n// after\nif (!process.env.VITEST) server.ws.send({ type: 'full-reload' })","handlingStrategy":"validation","validationCode":"transport: {\n  async invoke(event) {\n    if (event.type !== 'custom') return { error: new Error('HMR not supported') }\n    // ...\n  }\n}","typeGuard":"function isCustomEvent(event: any): boolean {\n  return event?.type === 'custom'\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["hmr","runner","vite","internal"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}