vitest-dev/vitest · error · Error

Can't find browser origin URL for project "${this.name}"

Error message

Can't find browser origin URL for project "${this.name}"

What it means

After confirming the browser exists, _openBrowserPage (project.ts:472-477) reads browser.vite.resolvedUrls to get the local or network origin. If both local[] and network[] are empty/undefined the test page URL cannot be constructed, so Vitest throws. This means the underlying Vite dev server never resolved its listening URLs.

Source

Thrown at packages/vitest/src/node/project.ts:475

  /** @internal */
  public _getViteEnvironments(): DevEnvironment[] {
    return Object.values(this.vite.environments || {})
  }

  /** @internal */
  public async _openBrowserPage(sessionId: string, pool: {
    reject: (error: Error) => void
    parallel?: boolean
  }): Promise<void> {
    if (!this.browser) {
      throw new Error(`browser is not initialized`)
    }

    const resolvedUrls = this.browser.vite.resolvedUrls
    const origin = resolvedUrls?.local[0] ?? resolvedUrls?.network[0]
    if (!origin) {
      throw new Error(
        `Can't find browser origin URL for project "${this.name}"`,
      )
    }

    const url = new URL('/__vitest_test__/', origin)
    url.searchParams.set('sessionId', sessionId)
    const otelCarrier = this.vitest._traces.getContextCarrier()
    this.vitest._browserSessions.sessionIds.add(sessionId)
    const sessionPromise = this.vitest._browserSessions.createSession(
      sessionId,
      this,
      pool,
      { otelCarrier },
    )
    const pagePromise = this.browser.provider.openPage(
      sessionId,
      url.toString(),
      { parallel: pool.parallel ?? false },

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Check the earlier server-start logs for an EADDRINUSE or listen error and free/switch the port (server.port or browser config).
  2. Ensure the Vite server is not closed/recreated between provider init and the first browser test.
  3. If using a custom server factory, verify it populates resolvedUrls.local.
  4. Run vitest with --no-watch and a single worker to rule out a restart race.

Example fix

// before
export default defineConfig({
  test: { browser: { enabled: true, provider: 'playwright', instances: [{ browser: 'chromium' }] } },
  server: { port: 5173 }, // collides
})

// after
export default defineConfig({
  test: { browser: { enabled: true, provider: 'playwright', instances: [{ browser: 'chromium' }] } },
  server: { port: 0 }, // let vitest pick a free port
})
Defensive patterns

Strategy: validation

Validate before calling

const urls = project.browser?.vite?.resolvedUrls
const origin = urls?.local?.[0] ?? urls?.network?.[0]
if (!origin) throw new Error('Vite server has no resolved URL; check port availability')

Type guard

function hasOrigin(urls: { local?: string[]; network?: string[] } | undefined): urls is { local: string[] } | { network: string[] } {
  return !!(urls?.local?.length || urls?.network?.length)
}

Prevention

When it happens

Trigger: The Vite dev server failed to bind a port (port in use, permission denied), the server was closed before the browser page opened, or server.resolvedUrls was reset. Also possible when a custom middleware/plugin clears resolvedUrls.

Common situations: Port 5173 (or configured port) already in use by another process; running in a CI sandbox that blocks the listen syscall; race condition closing the server between init and the first browser test; running headless without network permissions.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/7e3aa7aa474873a1.json. Report an issue: GitHub.