{"id":"333057fc28cade12","repo":"vitest-dev/vitest","slug":"unexpected-empty-queue","errorCode":null,"errorMessage":"Unexpected empty queue","messagePattern":"Unexpected empty queue","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/node/pools/browser.ts","lineNumber":370,"sourceCode":"      const isolate = this.project.config.isolate\n      // we don't need to cleanup testers if isolation is enabled,\n      // because cleanup is done at the end of every test\n      if (isolate) {\n        this.finishSession(sessionId)\n        return\n      }\n\n      // we need to cleanup testers first because there is only\n      // one iframe and it does the cleanup only after everything is completed\n      const orchestrator = this.getOrchestrator(sessionId)\n      orchestrator.cleanupTesters()\n        .catch(error => this.reject(error))\n        .finally(() => this.finishSession(sessionId))\n      return\n    }\n\n    if (!this._promise) {\n      throw new Error(`Unexpected empty queue`)\n    }\n\n    const orchestrator = this.getOrchestrator(sessionId)\n    debug?.('[%s] run test %s', sessionId, file)\n\n    // warm the transform cache while the iframe is booting so the test\n    // file import doesn't wait for the transform; mirrors the URL the\n    // tester will request (see `importFile` in the browser runner)\n    const fileUrl = `/${/^\\w:/.test(file.filepath) ? '@fs/' : ''}${file.filepath}`.replace(/\\/+/g, '/')\n    void this.project.vite.transformRequest(fileUrl).catch(() => {})\n\n    this.setBreakpoint(sessionId, file.filepath).then(() => {\n      // this starts running tests inside the orchestrator\n      const testersPromise = this._traces.$(\n        `vitest.browser.run`,\n        {\n          context: this._otel.context,\n          attributes: {","sourceCodeStart":352,"sourceCodeEnd":388,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/node/pools/browser.ts#L352-L388","documentation":"Internal assertion in BrowserPool.runNextTest: a file was just dequeued from this._queue, but this._promise is undefined. The promise is created at the start of runTests and is the resolve/reject handle for the whole batch; finding it absent while a file is being dispatched indicates the pool's internal state machine is inconsistent — treated as a framework bug.","triggerScenarios":"runNextTest is invoked (from a ready-session callback or page-ready callback) after the queue was already cleared/cancelled, so it shifts a file but the _promise was nulled by cancel()/reject()/finishSession at packages/vitest/src/node/pools/browser.ts:369-370.","commonSituations":"Cancellation racing with the run loop; a test completing and re-triggering runNextTest after the batch promise already resolved; browser disconnect during teardown.","solutions":["Report as a Vitest bug with a minimal browser test reproduction, focusing on cancel/re-run timing.","Retry — if it was triggered by a one-off browser disconnect it often does not recur.","Avoid triggering manual cancellation while browser tests are mid-run unless necessary."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await vitest.start()\n} catch (e) {\n  if (e.message === 'Unexpected empty queue') {\n    console.error('Browser pool state race — retry; if persistent, report with reproduction.')\n  }\n  throw e\n}","preventionTips":["Avoid manual cancellation while browser tests are mid-run unless necessary.","Retry transient occurrences (often one-off disconnect-driven races).","Pin a stable Vitest version; report persistent cases as bugs."],"tags":["browser","internal-bug","state-machine","assertion"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}