vitejs/vite · error · Error
HMR is not supported by this runner transport, but `hmr` opt
Error message
HMR is not supported by this runner transport, but `hmr` option was set to true
What it means
Thrown in the ModuleRunner constructor when options.hmr is not false (defaults to true) but the provided transport has no connect method. HMR requires a persistent connection to receive push notifications from the server, so the transport must implement connect(). If the transport only implements invoke (request-response pattern) without connect, HMR cannot function and the constructor fails immediately.
Source
Thrown at packages/vite/src/module-runner/runner.ts:74
private debug?: ModuleRunnerDebugger | undefined,
) {
this.evaluatedModules = options.evaluatedModules ?? new EvaluatedModules()
this.transport = normalizeModuleRunnerTransport(options.transport)
if (options.hmr !== false) {
const optionsHmr = options.hmr ?? true
const resolvedHmrLogger: HMRLogger =
optionsHmr === true || optionsHmr.logger === undefined
? hmrLogger
: optionsHmr.logger === false
? silentConsole
: optionsHmr.logger
this.hmrClient = new HMRClient(
resolvedHmrLogger,
this.transport,
({ acceptedPath }) => this.import(acceptedPath),
)
if (!this.transport.connect) {
throw new Error(
'HMR is not supported by this runner transport, but `hmr` option was set to true',
)
}
this.transport.connect(createHMRHandlerForRunner(this))
} else {
this.transport.connect?.()
}
if (options.sourcemapInterceptor !== false) {
this.resetSourceMapSupport = enableSourceMapSupport(this)
}
}
/**
* URL to execute. Accepts file path, server path or id relative to the root.
*/
public async import<T = any>(url: string): Promise<T> {
const fetchedModule = await this.cachedModule(url)
return await this.cachedRequest(url, fetchedModule)View on GitHub (pinned to 89620f09af)
Solutions
- Set hmr: false when creating the runner if your transport doesn't support connect: new ModuleRunner({ transport, hmr: false }).
- Implement a connect method on your transport (even a no-op if you handle messaging through invoke) if you need HMR.
- Use createWebSocketModuleRunnerTransport from Vite which provides a complete connect/disconnect/send implementation over WebSocket.
Example fix
// before — custom transport without connect, HMR enabled by default
const runner = new ModuleRunner({
transport: { invoke: myInvokeFn } // no connect
})
// after — explicitly disable HMR
const runner = new ModuleRunner({
transport: { invoke: myInvokeFn },
hmr: false
}) Defensive patterns
Strategy: validation
Validate before calling
// Validate transport supports HMR before creating the runner
function validateTransportForHmr(transport, hmrOption) {
if (hmrOption !== false && !transport.connect) {
throw new Error('Transport must implement connect() to support HMR. Set hmr: false to disable.')
}
}
// Or auto-resolve
const hmr = transport.connect ? (options.hmr ?? true) : false
const runner = new ModuleRunner({ transport, hmr }) Type guard
function transportSupportsHmr(transport: ModuleRunnerTransport): boolean {
return typeof transport.connect === 'function'
} Prevention
- Check typeof transport.connect === 'function' before enabling HMR.
- Use createWebSocketModuleRunnerTransport for a complete, HMR-capable transport.
- For request-response-only transports (invoke without connect), always set hmr: false.
- Document transport capabilities when building custom transports.
When it happens
Trigger: Creating a ModuleRunner with a custom transport that only implements invoke (or send) but not connect, while leaving hmr at its default (true) or explicitly setting hmr: true. Common when building a custom transport for request-response-only module loading (e.g., HTTP-based fetch without WebSocket).
Common situations: Using a custom ManuallyTriggeredTransport or HTTP-based transport that doesn't maintain a persistent connection. Integrating Vite's module runner in a non-standard runtime (e.g., serverless, edge) where WebSocket connections aren't available. Copying a transport implementation that omits connect.
Related errors
- Module "${url}" was mistakenly invalidated during fetch phas
- [module runner] Failed to load "${url}"${importer ? ` import
- [module runner] HMR client was closed.
- transport must implement send and connect when invoke is not
- send was called before connect
AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03).
Data as JSON: /data/errors/f02d1375e245935b.json.
Report an issue: GitHub.