vitest-dev/vitest · error · Error
The worker thread was torn down or never initialized. This i
Error message
The worker thread was torn down or never initialized. This is a bug in Vitest.
What it means
Internal assertion in the threads worker: the private _thread getter throws if the underlying Worker was never created (start() not called or failed) or was cleared (set to undefined after stop()). Used by on/off/send, so interacting with a torn-down worker thread trips it.
Source
Thrown at packages/vitest/src/node/pools/workers/threadsWorker.ts:74
async stop(): Promise<void> {
await this.thread.terminate()
this._thread?.stdout?.unpipe(this.stdout)
this.stdout.setMaxListeners(this.stdout.getMaxListeners() - 1)
this._thread?.stderr?.unpipe(this.stderr)
this.stderr.setMaxListeners(this.stderr.getMaxListeners() - 1)
this._thread = undefined
}
deserialize(data: unknown): unknown {
return data
}
private get thread() {
if (!this._thread) {
throw new Error(`The worker thread was torn down or never initialized. This is a bug in Vitest.`)
}
return this._thread
}
}
View on GitHub (pinned to d568f8ce37)
Solutions
- Report as a Vitest bug with reproduction (cancellation/teardown focus).
- Retry on transient Ctrl+C races.
- If using the @experimental ThreadsPoolWorker directly, never interact with the worker after stop().
Defensive patterns
Strategy: try-catch
Try / catch
try {
await vitest.start()
} catch (e) {
if (e.message === 'The worker thread was torn down or never initialized. This is a bug in Vitest.') {
console.error('Threads worker teardown race — retry; if persistent, report as a bug.')
}
throw e
} Prevention
- Pin stable Vitest versions to avoid teardown/postMessage races.
- Retry transient occurrences during cancellation.
- Never call ThreadsPoolWorker.send after stop() when using the experimental API.
When it happens
Trigger: ThreadsPoolWorker.on/off/send is called when this._thread is undefined — before start() or after stop() set it to undefined at packages/vitest/src/node/pools/workers/threadsWorker.ts:65-74. Same shape as the forks worker: a message posted to a stopped worker.
Common situations: Teardown/cancellation race where PoolRunner.postMessage runs after the thread was terminated; a regression in the STOPPED-state message gating; experimental API misuse sending after stop().
Related errors
- The child process was torn down or never initialized. This i
- [vitest-pool-runner]: Cannot start a stopped runner
- Unexpected message ${JSON.stringify(message, null, 2)}
- Cannot find the environment. This is a bug in Vitest.
- The browser server was not initialized${project.name ? ` for
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/1c5beba084592d9e.json.
Report an issue: GitHub.