{"id":"f02d1375e245935b","repo":"vitejs/vite","slug":"hmr-is-not-supported-by-this-runner-transport-but","errorCode":null,"errorMessage":"HMR is not supported by this runner transport, but `hmr` option was set to true","messagePattern":"HMR is not supported by this runner transport, but `hmr` option was set to true","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vite/src/module-runner/runner.ts","lineNumber":74,"sourceCode":"    private debug?: ModuleRunnerDebugger | undefined,\n  ) {\n    this.evaluatedModules = options.evaluatedModules ?? new EvaluatedModules()\n    this.transport = normalizeModuleRunnerTransport(options.transport)\n    if (options.hmr !== false) {\n      const optionsHmr = options.hmr ?? true\n      const resolvedHmrLogger: HMRLogger =\n        optionsHmr === true || optionsHmr.logger === undefined\n          ? hmrLogger\n          : optionsHmr.logger === false\n            ? silentConsole\n            : optionsHmr.logger\n      this.hmrClient = new HMRClient(\n        resolvedHmrLogger,\n        this.transport,\n        ({ acceptedPath }) => this.import(acceptedPath),\n      )\n      if (!this.transport.connect) {\n        throw new Error(\n          'HMR is not supported by this runner transport, but `hmr` option was set to true',\n        )\n      }\n      this.transport.connect(createHMRHandlerForRunner(this))\n    } else {\n      this.transport.connect?.()\n    }\n    if (options.sourcemapInterceptor !== false) {\n      this.resetSourceMapSupport = enableSourceMapSupport(this)\n    }\n  }\n\n  /**\n   * URL to execute. Accepts file path, server path or id relative to the root.\n   */\n  public async import<T = any>(url: string): Promise<T> {\n    const fetchedModule = await this.cachedModule(url)\n    return await this.cachedRequest(url, fetchedModule)","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/vitejs/vite/blob/89620f09afcfef6b35e7bb8660132ab5b4d0cd3b/packages/vite/src/module-runner/runner.ts#L56-L92","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before — custom transport without connect, HMR enabled by default\nconst runner = new ModuleRunner({\n  transport: { invoke: myInvokeFn } // no connect\n})\n// after — explicitly disable HMR\nconst runner = new ModuleRunner({\n  transport: { invoke: myInvokeFn },\n  hmr: false\n})","handlingStrategy":"validation","validationCode":"// Validate transport supports HMR before creating the runner\nfunction validateTransportForHmr(transport, hmrOption) {\n  if (hmrOption !== false && !transport.connect) {\n    throw new Error('Transport must implement connect() to support HMR. Set hmr: false to disable.')\n  }\n}\n\n// Or auto-resolve\nconst hmr = transport.connect ? (options.hmr ?? true) : false\nconst runner = new ModuleRunner({ transport, hmr })","typeGuard":"function transportSupportsHmr(transport: ModuleRunnerTransport): boolean {\n  return typeof transport.connect === 'function'\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["module-runner","hmr","transport","config"],"analyzedSha":"89620f09afcfef6b35e7bb8660132ab5b4d0cd3b","analyzedAt":"2026-08-03T19:28:02.920Z","schemaVersion":2}