vitest-dev/vitest · error · Error

vitest/browser can be imported only inside the Browser Mode.

Error message

vitest/browser can be imported only inside the Browser Mode. ${pool ? `Your test is running in ${pool} pool. Make sure your regular tests are excluded from the "test.include" glob pattern.` : 'Instead, it was imported outside of Vitest.'}

What it means

Thrown at module-evaluation time in packages/vitest/browser/context.js — the file is the stub Vitest serves whenever a test imports 'vitest/browser' but is not actually running in the browser pool. The stub reads the current worker's pool name and throws, tailoring the message: if a pool is set, it tells you the test is running in the wrong pool (e.g. forks/threads) and that your regular tests are catching the browser include glob; otherwise it notes the import happened outside Vitest entirely.

Source

Thrown at packages/vitest/browser/context.js:14

// Vitest resolves "vitest/browser" as a virtual module instead

// fake exports for static analysis
export const page = null
export const server = null
export const userEvent = null
export const cdp = null
export const commands = null
export const locators = null
export const utils = null

const pool = globalThis.__vitest_worker__?.ctx?.pool

throw new Error(
  // eslint-disable-next-line prefer-template
  'vitest/browser can be imported only inside the Browser Mode. '
  + (pool
    ? `Your test is running in ${pool} pool. Make sure your regular tests are excluded from the "test.include" glob pattern.`
    : 'Instead, it was imported outside of Vitest.'),
)

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Split test.include into separate globs for browser and Node tests, or add an env/projects config so browser specs only run under the browser project.
  2. Move 'vitest/browser' imports out of shared utilities and into browser-only test files.
  3. Run browser tests with a dedicated project: defineProjects([{ test: { name: 'browser', browser: { enabled: true, instances: [...] }, include: ['**/*.browser.test.ts'] } }]).
  4. If you imported it outside Vitest, remove the import — the browser API is only meaningful under the browser provider.

Example fix

// vitest.config.ts — before
test: { include: ['**/*.test.ts'], browser: { enabled: true, instances: [{ browser: 'chromium' }] } }

// after — separate projects
export default defineConfig({
  test: {
    projects: [
      { test: { name: 'node', include: ['test/**/*.node.test.ts'] } },
      { test: { name: 'browser', include: ['test/**/*.browser.test.ts'], browser: { enabled: true, instances: [{ browser: 'chromium' }], provider: playwright() } } },
    ],
  },
})
Defensive patterns

Strategy: validation

Validate before calling

function isBrowserPool(): boolean {
  return globalThis.__vitest_worker__?.ctx?.pool === 'browser'
}
if (!isBrowserPool()) {
  throw new Error('vitest/browser imports require the browser pool')
}

Type guard

interface VitestWorker { ctx?: { pool?: string } }
function isBrowserWorker(g: typeof globalThis): g is typeof globalThis & { __vitest_worker__: VitestWorker } {
  return (g as any).__vitest_worker__?.ctx?.pool === 'browser'
}

Prevention

When it happens

Trigger: import { page, userEvent } from 'vitest/browser' in a test that runs under the default (threads/forks) pool; a shared utility imported by both Node tests and browser tests that pulls from 'vitest/browser'; test.include glob broad enough to feed browser-only specs into the regular runner.

Common situations: Enabling browser mode without excluding browser specs from the regular test run; sharing helper modules across Node and browser tests; importing the browser API in setup files that also run for non-browser tests.

Related errors


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