{"record":{"id":"cebefaa8c59ccb30","repo":"moeru-ai/airi","slug":"vite-did-not-expose-a-reachable-dev-server-url","errorCode":null,"errorMessage":"Vite did not expose a reachable dev server URL.","messagePattern":"Vite did not expose a reachable dev server URL\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cap-vite/src/native.ts","lineNumber":165,"sourceCode":"      return capArgs\n    }\n\n    const targets = await listTargets(platform)\n    target = targets.find(device => device.id)?.id\n  }\n\n  if (!target) {\n    throw new Error(`No ${platform} devices or simulators found. Connect a device, start a simulator or emulator, or pass --target explicitly.`)\n  }\n\n  return [platformArg, '--target', target, ...rest]\n}\n\nexport function pickServerUrl(server: Pick<ViteDevServer, 'resolvedUrls'>): URL {\n  const url = server.resolvedUrls?.network?.[0] ?? server.resolvedUrls?.local?.[0]\n\n  if (!url) {\n    throw new Error('Vite did not expose a reachable dev server URL.')\n  }\n\n  return new URL(url)\n}\n\nexport function shouldRestartForNativeChange(file: string, platform: CapacitorPlatform, cwd: string): boolean {\n  const absoluteFile = resolve(cwd, file)\n  const platformRoot = resolve(cwd, platform)\n\n  if (!absoluteFile.startsWith(`${platformRoot}${sep}`) && absoluteFile !== platformRoot) {\n    return false\n  }\n\n  const fileName = basename(absoluteFile)\n\n  if (ignoredNames.has(fileName)) {\n    return false\n  }","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/cap-vite/src/native.ts#L147-L183","documentation":"Thrown by pickServerUrl() when the Vite dev server exposes neither resolvedUrls.network nor resolvedUrls.local. cap-vite uses this URL to tell `cap run` where to load the bundled app from, so an absent URL makes the run target undefined.","triggerScenarios":"Calling pickServerUrl(server) before the Vite server has finished binding its URLs; a Vite server configuration with server.host/server.port set in a way that prevents resolvedUrls from being populated; accessing the server in a context where listen() was never called or was closed.","commonSituations":"Custom Vite plugin that calls pickServerUrl in configureServer before the next tick when resolvedUrls are assigned; middleware mode servers that never call listen(); server.hmr.server misconfigured to a broken WebSocket; race after server.close().","solutions":["Ensure pickServerUrl is called after Vite has started listening (e.g. await server.listen() or inside a then resolvedUrls is set).","Check vite config: server.host and server.port must permit a bound socket; avoid server.middlewareMode: true unless you manage URLs yourself.","If using HMR over a custom server, verify server.hmr.server resolves so Vite can compute local/network URLs."],"exampleFix":"// before\nconst url = pickServerUrl(server) // called too early in configureServer\n// after\nserver.httpServer?.once('listening', () => {\n  const url = pickServerUrl(server)\n  startCapProcess(cwd, capArgs, url)\n})","handlingStrategy":"validation","validationCode":"function hasResolvedUrl(server: { resolvedUrls?: { network?: string[]; local?: string[] } }): boolean {\n  return !!(server.resolvedUrls?.network?.[0] ?? server.resolvedUrls?.local?.[0])\n}\n\nif (!hasResolvedUrl(server)) throw new Error('Vite server has no resolved URL yet')","typeGuard":null,"tryCatchPattern":"try {\n  const url = pickServerUrl(server)\n} catch (error) {\n  if (error instanceof Error && error.message.includes('reachable dev server URL')) {\n    // wait for listening and retry once\n  }\n}","preventionTips":["Call pickServerUrl only after server.listen() has resolved or the 'listening' event fired.","Avoid server.middlewareMode unless you manage URLs yourself.","Log server.resolvedUrls during dev to catch empty states early."],"tags":["vite","dev-server","capacitor","lifecycle"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}