{"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":"Error","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/677329427f32468c74b17f3ec47eeca4e05bec65/packages/cap-vite/src/native.ts#L147-L183","documentation":"pickServerUrl reads ViteDevServer.resolvedUrls.network[0] falling back to local[0] and throws when both are absent — i.e. the running Vite server never exposed any reachable URL. cap-vite needs that URL to point the native app at the dev server.","triggerScenarios":"Using the plugin with a Vite server created in middlewareMode (resolvedUrls stays null/empty), picking the URL before server.listen() completed, or a server config that prevents URL resolution (failed port binding with strictPort, unusual host config).","commonSituations":"Embedding cap-vite's plugin in a custom programmatic server setup instead of a normal `vite` dev run; racing the URL read against server startup; config that disables or alters server URL resolution.","solutions":["Run a normal Vite dev server (not middleware mode) so resolvedUrls gets populated after listen()","Only read the URL after the server is listening (await server.listen() or inside the post-listen hook)","Fix underlying listen failures first (port in use + strictPort, bad server.host value)"],"exampleFix":"// before (middleware mode — resolvedUrls never populated)\nconst server = await createViteServer({ server: { middlewareMode: true }, plugins: [capVitePlugin({ capArgs: ['ios'] })] })\nconst url = pickServerUrl(server) // Error: Vite did not expose a reachable dev server URL.\n\n// after\nconst server = await createViteServer({ server: { host: true }, plugins: [capVitePlugin({ capArgs: ['ios'] })] })\nawait server.listen()\nconst url = pickServerUrl(server) // resolvedUrls.local/network now set","handlingStrategy":"validation","validationCode":"// Only pick the URL once Vite actually resolved one\nconst urls = server.resolvedUrls?.network ?? server.resolvedUrls?.local\nif (!urls?.length)\n  throw new Error('Dev server not listening yet — call this after server.listen()')\nconst url = pickServerUrl(server)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid middlewareMode when using cap-vite's plugin; run a normal dev server","Read resolvedUrls only after listen() resolves","Fix port-binding failures (strictPort + occupied port) before blaming the picker"],"tags":["vite","dev-server","urls"],"backgroundTag":"dev-server-url-unavailable","analyzedSha":"677329427f32468c74b17f3ec47eeca4e05bec65","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}