vitest-dev/vitest · critical · Error
Expected worker to be run in node:worker_threads
Error message
Expected worker to be run in node:worker_threads
What it means
Module-level guard in init-threads.ts (line 6-8): the threads worker entrypoint requires both isMainThread === false and a non-null parentPort, i.e. it must run inside a node:worker_threads Worker. Importing it in the main thread or a child process throws at import time.
Source
Thrown at packages/vitest/src/runtime/workers/init-threads.ts:7
import type { WorkerGlobalState, WorkerSetupContext } from '../../types/worker'
import type { Traces } from '../../utils/traces'
import { isMainThread, parentPort } from 'node:worker_threads'
import { init } from './init'
if (isMainThread || !parentPort) {
throw new Error('Expected worker to be run in node:worker_threads')
}
export default function workerInit(options: {
runTests: (method: 'run' | 'collect', state: WorkerGlobalState, traces: Traces) => Promise<void>
setup?: (context: WorkerSetupContext) => void | Promise<() => Promise<unknown>>
}): void {
const { runTests } = options
init({
post: response => parentPort!.postMessage(response),
on: callback => parentPort!.on('message', callback),
off: callback => parentPort!.off('message', callback),
teardown: () => parentPort!.removeAllListeners('message'),
runTests: async (state, traces) => runTests('run', state, traces),
collectTests: async (state, traces) => runTests('collect', state, traces),
setup: options.setup,
})
}View on GitHub (pinned to d568f8ce37)
Solutions
- Do not import init-threads directly; let Vitest spawn the worker via pool: 'threads'.
- If building a custom pool, load the threads entry only inside `new Worker(...)`.
- Switch to pool: 'forks' if you intended to use child processes.
Example fix
// before: importing threads entry in main thread
import workerInit from 'vitest/dist/workers/threads.js'
// after: configure vitest to spawn the worker
// vitest.config.ts
export default defineConfig({ test: { pool: 'threads' } }) Defensive patterns
Strategy: validation
Validate before calling
import { isMainThread, parentPort } from 'node:worker_threads'
function assertWorkerThreadContext() {
if (isMainThread || !parentPort) {
throw new Error(
'init-threads must be loaded inside a Worker (worker_threads); do not import it from the main thread.'
)
}
} Prevention
- Only load the threads worker entry inside `new Worker(...)`.
- Keep pool configuration declarative via test.pool rather than manual imports.
- Document clearly which entry files are process-entry-only when forking vitest internals.
When it happens
Trigger: Importing the threads worker entry (init-threads.ts or the built runThreadsTests file) from the main thread, a forked child_process, or any non-worker-thread context where isMainThread is true or parentPort is null.
Common situations: A custom pool pointing at the threads entry but spawning a fork; tests or scripts that import internal vitest worker modules; experimentation with the worker init code outside a Worker.
Related errors
- Expected worker to be run in node:child_process
- Tag "${tag.name}": retry.condition function cannot be used i
- You cannot use ${inspectOption} without "--no-file-paralleli
- "snapshotFormat.compareKeys" function is not supported.
- Expected string coverage payload, received ${typeof coverage
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/dce5a470f6421f0a.json.
Report an issue: GitHub.