vitest-dev/vitest · error · Error

[vitest-pool]: Cannot run tasks while pool is cancelling

Error message

[vitest-pool]: Cannot run tasks while pool is cancelling

What it means

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.

Source

Thrown at packages/vitest/src/node/pools/pool.ts:54

  private activeTasks: ActiveTask[] = []
  private sharedRunners: PoolRunner[] = []
  private exitPromises: Promise<void>[] = []
  private _isCancelling: boolean = false

  constructor(private options: Options, private logger: Logger) {}

  setMaxWorkers(maxWorkers: number): void {
    this.maxWorkers = maxWorkers

    this.workerIds = new Map(
      Array.from({ length: maxWorkers }).fill(0).map((_, i) => [i + 1, true]),
    )
  }

  async run(task: PoolTask, method: 'run' | 'collect'): Promise<void> {
    // Prevent new tasks from being queued during cancellation
    if (this._isCancelling) {
      throw new Error('[vitest-pool]: Cannot run tasks while pool is cancelling')
    }

    // Every runner related failure should make this promise reject so that it's picked by pool.
    // This resolver is used to make the error handling in recursive queue easier.
    const testFinish = withResolvers()

    this.queue.push({ task, resolver: testFinish, method })
    void this.schedule()

    await testFinish.promise
  }

  private async schedule(): Promise<void> {
    if (this.queue.length === 0 || this.activeTasks.length >= this.maxWorkers) {
      return
    }

    const { task, resolver, method } = this.queue.shift()!

View on GitHub (pinned to d568f8ce37)

Solutions

  1. If calling the Vitest API programmatically, await vitest.cancelCurrentRun() fully before starting a new run.
  2. Guard re-submission by checking vitest.isCancelling before queueing more tests.
  3. For interactive use, allow the current cancel to finish before re-running (single Ctrl+C, then re-run).
  4. Report an internal race if this fires during normal CLI usage with no concurrent API calls.

Example fix

// before: starting a run while a cancel is in flight
vitest.cancelCurrentRun('user')
await vitest.start('path/to/file.test.ts')

// after: await cancellation completion first
await vitest.cancelCurrentRun('user')
if (!vitest.isCancelling) {
  await vitest.start('path/to/file.test.ts')
}
Defensive patterns

Strategy: validation

Validate before calling

// Programmatic API: guard start() against an in-flight cancel
async function safeStart(vitest, files) {
  await vitest.cancelCurrentRun('reset')
  if (vitest.isCancelling) {
    throw new Error('Cannot start: a cancellation is still in progress')
  }
  await vitest.start(files)
}

Try / catch

try {
  await vitest.start()
} catch (e) {
  if (e.message === '[vitest-pool]: Cannot run tasks while pool is cancelling') {
    // wait for cancellation to settle, then retry once
    await new Promise(r => setTimeout(r, 100))
  } else throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/d1ca66ada9467520.json. Report an issue: GitHub.