{"id":"1e58dce6ca900be2","repo":"vitest-dev/vitest","slug":"vitest-web-worker-cannot-initiate-a-custom-web","errorCode":null,"errorMessage":"[@vitest/web-worker] Cannot initiate a custom Web Worker. \"${name}\" is not supported in this environment. Please, consider using jsdom or happy-dom environment.","messagePattern":"\\[@vitest/web-worker\\] Cannot initiate a custom Web Worker\\. \"(.+?)\" is not supported in this environment\\. Please, consider using jsdom or happy-dom environment\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/web-worker/src/utils.ts","lineNumber":10,"sourceCode":"import type { Debugger } from 'obug'\nimport type { CloneOption } from './types'\nimport ponyfillStructuredClone from '@ungap/structured-clone'\nimport { createDebug } from 'obug'\n\nexport const debug: Debugger = createDebug('vitest:web-worker')\n\nexport function assertGlobalExists(name: string): void {\n  if (!(name in globalThis)) {\n    throw new Error(\n      `[@vitest/web-worker] Cannot initiate a custom Web Worker. \"${name}\" is not supported in this environment. Please, consider using jsdom or happy-dom environment.`,\n    )\n  }\n}\n\nfunction createClonedMessageEvent(\n  data: any,\n  transferOrOptions: StructuredSerializeOptions | Transferable[] | undefined,\n  clone: CloneOption,\n) {\n  const transfer = Array.isArray(transferOrOptions)\n    ? transferOrOptions\n    : transferOrOptions?.transfer\n\n  debug('clone worker message %o', data)\n  const origin = typeof location === 'undefined' ? undefined : location.origin\n  const ports = transfer?.filter((t): t is MessagePort => t instanceof MessagePort)\n","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/web-worker/src/utils.ts#L1-L28","documentation":"defineWebWorkers (packages/web-worker/src/pure.ts:6-24) installs the Worker/SharedWorker constructors only when the current runtime lacks them. Before installing, it calls assertGlobalExists('EventTarget') and assertGlobalExists('MessageEvent') (utils.ts:8-14) because Vitest's worker shim is built on top of those primitives. If the named global is missing from globalThis, the function throws this Error telling the user which environment primitives are unavailable.","triggerScenarios":"Calling `import { defineWebWorkers } from '@vitest/web-worker'` followed by `defineWebWorkers()` (often via the `@vitest/web-worker` browser plugin or setup file) while the test `environment` is set to 'node' or any environment that does not expose EventTarget/MessageEvent on globalThis. The check runs at setup time, so the error surfaces as soon as the web-worker plugin initializes.","commonSituations":"Forgetting to set `test.environment: 'happy-dom'` or `'jsdom'` in vitest.config when tests use web workers; switching a project's environment from jsdom to node to speed up tests and forgetting the worker setup; running in a minimal custom environment that polyfills fetch but not EventTarget/MessageEvent; version upgrade that moved the defineWebWorkers call earlier in setup.","solutions":["Set the test environment to a DOM-providing one in vitest.config.ts: `test: { environment: 'happy-dom' }` (or 'jsdom').","Install the missing environment package if not present (`npm i -D jsdom` or `npm i -D @happy-dom/global-registrator`).","If you intentionally run in node, ensure your setup file polyfills EventTarget and MessageEvent on globalThis before calling defineWebWorkers.","Confirm the environment name in config is spelled correctly — a typo silently falls back to node and trips this assertion."],"exampleFix":"// before — vitest.config.ts\nimport { defineConfig } from 'vitest/config'\nexport default defineConfig({\n  test: { environment: 'node', setupFiles: ['@vitest/web-worker'] },\n})\n\n// after — provide EventTarget + MessageEvent via a DOM environment\nimport { defineConfig } from 'vitest/config'\nexport default defineConfig({\n  test: { environment: 'happy-dom', setupFiles: ['./setup.ts'] },\n})\n// setup.ts\nimport { defineWebWorkers } from '@vitest/web-worker'\ndefineWebWorkers()","handlingStrategy":"validation","validationCode":"// Verify the environment has the globals defineWebWorkers needs BEFORE\n// importing @vitest/web-worker. Mirrors utils.ts assertGlobalExists.\nfunction canDefineWebWorkers() {\n  return (\n    typeof globalThis !== 'undefined' &&\n    'EventTarget' in globalThis &&\n    'MessageEvent' in globalThis\n  )\n}\nif (!canDefineWebWorkers()) {\n  throw new Error(\n    'Set test.environment to happy-dom or jsdom before using @vitest/web-worker.',\n  )\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always declare `test.environment: 'happy-dom'` (or 'jsdom') in vitest.config when tests use web workers.","Keep `defineWebWorkers()` in a setup file that loads AFTER the DOM environment is registered.","Add a CI guard that fails fast if the environment is 'node' while @vitest/web-worker is a dependency."],"tags":["web-worker","environment","jsdom","happy-dom","setup"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}