{"id":"6ede1e97c5d28599","repo":"vitest-dev/vitest","slug":"expected-worker-to-be-run-in-node-child-process","errorCode":null,"errorMessage":"Expected worker to be run in node:child_process","messagePattern":"Expected worker to be run in node:child_process","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/vitest/src/runtime/workers/init-forks.ts","lineNumber":6,"sourceCode":"import type { WorkerGlobalState, WorkerSetupContext } from '../../types/worker'\nimport type { Traces } from '../../utils/traces'\nimport { init } from './init'\n\nif (!process.send) {\n  throw new Error('Expected worker to be run in node:child_process')\n}\n\n// Store globals in case tests overwrite them\nconst processExit = process.exit.bind(process)\nconst processSend = process.send.bind(process)\nconst processOn = process.on.bind(process)\nconst processOff = process.off.bind(process)\nconst processRemoveAllListeners = process.removeAllListeners.bind(process)\n\nconst isProfiling = process.execArgv.some(\n  execArg =>\n    execArg.startsWith('--prof')\n    || execArg.startsWith('--cpu-prof')\n    || execArg.startsWith('--heap-prof')\n    || execArg.startsWith('--diagnostic-dir'),\n)\n\n// Work-around for nodejs/node#55094","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/runtime/workers/init-forks.ts#L1-L24","documentation":"Module-level guard in init-forks.ts (line 5-7): the forks worker entrypoint requires process.send to exist, which is only present when the process is spawned as a node:child_process fork. If the file is imported in any other context it throws immediately at import time.","triggerScenarios":"Importing packages/vitest .../workers/init-forks.ts (or the built runForksTests entry) directly from the main process, a worker thread, or a normal script — anywhere process.send is undefined. Vitest itself only loads this file inside a forked child of the forks pool.","commonSituations":"A custom pool or test that imports the forks worker module to reuse its logic; a misconfigured pool that points at the forks entry but spawns a worker_thread instead of a fork; importing internal vitest paths for experimentation.","solutions":["Do not import init-forks directly; let Vitest spawn the fork via pool: 'forks'.","If building a custom pool that uses child_process.fork, ensure the entry is only loaded inside the forked process.","Switch the pool to 'threads' if you actually want worker_threads."],"exampleFix":"// before: importing the forks entry in the main process\nimport './node_modules/vitest/dist/workers/forks.js'\n\n// after: let vitest fork it via config\n// vitest.config.ts\nexport default defineConfig({ test: { pool: 'forks' } })","handlingStrategy":"validation","validationCode":"import { isMainThread } from 'node:worker_threads'\n\nfunction assertForkContext() {\n  const isForkedChild = typeof process.send === 'function'\n  if (!isForkedChild && isMainThread) {\n    throw new Error(\n      'init-forks must be loaded inside a child_process.fork; do not import it from the main process.'\n    )\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never import vitest internal worker entry files from application or test code.","When building a custom pool, spawn the entry via child_process.fork and load it only there.","Treat pool selection as a config-only concern (test.pool) rather than a code import."],"tags":["forks-pool","worker","child-process","import-guard"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}