{"id":"409372ccec371539","repo":"vitest-dev/vitest","slug":"the-child-process-was-torn-down-or-never-initializ","errorCode":null,"errorMessage":"The child process was torn down or never initialized. This is a bug in Vitest.","messagePattern":"The child process was torn down or never initialized\\. This is a bug in Vitest\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/pools/workers/forksWorker.ts","lineNumber":108,"sourceCode":"      fork.stdout?.unpipe(this.stdout)\n      this.stdout.setMaxListeners(this.stdout.getMaxListeners() - 1)\n    }\n\n    if (fork.stderr) {\n      fork.stderr?.unpipe(this.stderr)\n      this.stderr.setMaxListeners(this.stderr.getMaxListeners() - 1)\n    }\n\n    this._fork = undefined\n  }\n\n  deserialize(data: unknown): unknown {\n    return data\n  }\n\n  private get fork() {\n    if (!this._fork) {\n      throw new Error(`The child process was torn down or never initialized. This is a bug in Vitest.`)\n    }\n    return this._fork\n  }\n}\n","sourceCodeStart":90,"sourceCodeEnd":113,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/node/pools/workers/forksWorker.ts#L90-L113","documentation":"Internal assertion in the forks worker: the private _fork getter throws if the underlying ChildProcess was never created (start() not called or failed) or was cleared (set to undefined after stop()). The getter is used by on/off/send, so any message interaction with a non-running forked process trips it.","triggerScenarios":"ForksPoolWorker.on/off/send is called when this._fork is undefined — either before start() ran or after stop() set it to undefined at packages/vitest/src/node/pools/workers/forksWorker.ts:99-108. Indicates the runner sent a message to a torn-down worker.","commonSituations":"A race where the pool/runner posts a message after worker.stop() completed; stop() running during cancellation while a queued message is still in flight; a regression in PoolRunner.postMessage gating (it should drop messages when STOPPED).","solutions":["Report as a Vitest bug with reproduction (focus on cancellation/teardown timing).","Retry — transient teardown races during Ctrl+C can surface this once.","If using the @experimental ForksPoolWorker directly, never send before start() or after stop()."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await vitest.start()\n} catch (e) {\n  if (e.message === 'The child process was torn down or never initialized. This is a bug in Vitest.') {\n    console.error('Forks worker teardown race — retry; if persistent, report as a bug.')\n  }\n  throw e\n}","preventionTips":["Pin stable Vitest versions to avoid teardown/postMessage races.","Retry transient occurrences during Ctrl+C cancellation.","Never call ForksPoolWorker.send after stop() when using the experimental API."],"tags":["worker","forks","internal-bug","lifecycle","assertion"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}