vitest-dev/vitest · error · Error

[@vitest/web-worker] Cannot initiate a custom Web Worker.

Error message

[@vitest/web-worker] Cannot initiate a custom Web Worker. "${name}" is not supported in this environment. Please, consider using jsdom or happy-dom environment.

What it means

assertGlobalExists guards the custom Worker constructor: @vitest/web-worker needs browser globals (such as Worker, MessageChannel, structuredClone) to exist on globalThis. In a bare Node test environment those globals are absent, so the helper throws this error at construction time, before any worker code runs, and points to jsdom or happy-dom as the fix.

Solutions

  1. Switch the Vitest environment to a DOM provider: set environment: 'jsdom' (or 'happy-dom') in the config, or pass --environment happy-dom.
  2. Install the environment package: npm i -D jsdom (or happy-dom).
  3. Scope it per file with a comment directive at the top of the test: // @vitest-environment happy-dom.

Example fix

// before
// @vitest-environment node
new MyWorker(url)  // throws

// after
// @vitest-environment happy-dom
new MyWorker(url)
Defensive patterns

Strategy: validation

Validate before calling

function environmentSupportsWorker() {
  return typeof globalThis !== 'undefined'
    && 'Worker' in globalThis
}
if (!environmentSupportsWorker()) {
  throw new Error('Current Vitest environment lacks Worker; set environment to jsdom or happy-dom.')
}

Type guard

function hasWorkerGlobal(g: typeof globalThis): g is typeof globalThis & { Worker: typeof Worker } {
  return typeof g !== 'undefined' && 'Worker' in g
}

Try / catch

try {
  const worker = new CustomWorker(url)
} catch (e) {
  if (e instanceof Error && /not supported in this environment/.test(e.message)) {
    console.warn('Skipping worker test: set // @vitest-environment happy-dom')
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Instantiating a Worker through the @vitest/web-worker constructor while the Vitest environment is node (no DOM shim). The check runs synchronously during Worker construction, via assertGlobalExists called with the missing global name.

Common situations: Default environment left as node; forgot to set jsdom or happy-dom; an environment shim package is missing or an incompatible version that does not define the required global; an SSR-style test that imports worker code incidentally.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/1e58dce6ca900be2. Report an issue: GitHub.

Appendix: source

Thrown at packages/web-worker/src/utils.ts:10

import type { Debugger } from 'obug'
import type { CloneOption } from './types'
import ponyfillStructuredClone from '@ungap/structured-clone'
import { createDebug } from 'obug'

export const debug: Debugger = createDebug('vitest:web-worker')

export function assertGlobalExists(name: string): void {
  if (!(name in globalThis)) {
    throw new Error(
      `[@vitest/web-worker] Cannot initiate a custom Web Worker. "${name}" is not supported in this environment. Please, consider using jsdom or happy-dom environment.`,
    )
  }
}

function createClonedMessageEvent(
  data: any,
  transferOrOptions: StructuredSerializeOptions | Transferable[] | undefined,
  clone: CloneOption,
) {
  const transfer = Array.isArray(transferOrOptions)
    ? transferOrOptions
    : transferOrOptions?.transfer

  debug('clone worker message %o', data)
  const origin = typeof location === 'undefined' ? undefined : location.origin
  const ports = transfer?.filter((t): t is MessagePort => t instanceof MessagePort)

View on GitHub (pinned to 1fa9837ec2)