{"id":"d1ca66ada9467520","repo":"vitest-dev/vitest","slug":"vitest-pool-cannot-run-tasks-while-pool-is-canc","errorCode":null,"errorMessage":"[vitest-pool]: Cannot run tasks while pool is cancelling","messagePattern":"\\[vitest-pool\\]: Cannot run tasks while pool is cancelling","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/pools/pool.ts","lineNumber":54,"sourceCode":"  private activeTasks: ActiveTask[] = []\n  private sharedRunners: PoolRunner[] = []\n  private exitPromises: Promise<void>[] = []\n  private _isCancelling: boolean = false\n\n  constructor(private options: Options, private logger: Logger) {}\n\n  setMaxWorkers(maxWorkers: number): void {\n    this.maxWorkers = maxWorkers\n\n    this.workerIds = new Map(\n      Array.from({ length: maxWorkers }).fill(0).map((_, i) => [i + 1, true]),\n    )\n  }\n\n  async run(task: PoolTask, method: 'run' | 'collect'): Promise<void> {\n    // Prevent new tasks from being queued during cancellation\n    if (this._isCancelling) {\n      throw new Error('[vitest-pool]: Cannot run tasks while pool is cancelling')\n    }\n\n    // Every runner related failure should make this promise reject so that it's picked by pool.\n    // This resolver is used to make the error handling in recursive queue easier.\n    const testFinish = withResolvers()\n\n    this.queue.push({ task, resolver: testFinish, method })\n    void this.schedule()\n\n    await testFinish.promise\n  }\n\n  private async schedule(): Promise<void> {\n    if (this.queue.length === 0 || this.activeTasks.length >= this.maxWorkers) {\n      return\n    }\n\n    const { task, resolver, method } = this.queue.shift()!","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/node/pools/pool.ts#L36-L72","documentation":"Thrown by Pool.run when a new task is submitted while the pool is in the middle of cancelling (_isCancelling is true). During cancellation the pool drains its queue and stops active runners; accepting new tasks would corrupt that teardown, so it is rejected outright.","triggerScenarios":"pool.run(task, method) is called after pool.cancel() has set _isCancelling = true but before cancel() finishes and resets the flag (packages/vitest/src/node/pools/pool.ts:52-54). This happens when executeTests schedules the next group of tasks while a prior cancel signal (e.g. Ctrl+C) is being processed.","commonSituations":"Pressing Ctrl+C during a run and a watcher/queue immediately re-submitting tasks; programmatic API usage that calls start()/runTestFiles concurrently with cancelCurrentRun; an internal scheduling race in watch mode.","solutions":["If calling the Vitest API programmatically, await vitest.cancelCurrentRun() fully before starting a new run.","Guard re-submission by checking vitest.isCancelling before queueing more tests.","For interactive use, allow the current cancel to finish before re-running (single Ctrl+C, then re-run).","Report an internal race if this fires during normal CLI usage with no concurrent API calls."],"exampleFix":"// before: starting a run while a cancel is in flight\nvitest.cancelCurrentRun('user')\nawait vitest.start('path/to/file.test.ts')\n\n// after: await cancellation completion first\nawait vitest.cancelCurrentRun('user')\nif (!vitest.isCancelling) {\n  await vitest.start('path/to/file.test.ts')\n}","handlingStrategy":"validation","validationCode":"// Programmatic API: guard start() against an in-flight cancel\nasync function safeStart(vitest, files) {\n  await vitest.cancelCurrentRun('reset')\n  if (vitest.isCancelling) {\n    throw new Error('Cannot start: a cancellation is still in progress')\n  }\n  await vitest.start(files)\n}","typeGuard":null,"tryCatchPattern":"try {\n  await vitest.start()\n} catch (e) {\n  if (e.message === '[vitest-pool]: Cannot run tasks while pool is cancelling') {\n    // wait for cancellation to settle, then retry once\n    await new Promise(r => setTimeout(r, 100))\n  } else throw e\n}","preventionTips":["Await cancelCurrentRun fully before starting a new run via the API.","Check vitest.isCancelling before scheduling subsequent runs.","Avoid rapid Ctrl+C + immediate re-run in watch mode."],"tags":["pool","cancellation","concurrency","scheduling"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}