{"record":{"id":"dd742fa71633de0d","repo":"vitest-dev/vitest","slug":"vitest-the-provider-was-closed","errorCode":null,"errorMessage":"[vitest] The provider was closed.","messagePattern":"\\[vitest\\] The provider was closed\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/browser-playwright/src/playwright.ts","lineNumber":656,"sourceCode":"  }\n\n  async openPage(sessionId: string, url: string, options: { parallel: boolean }): Promise<void> {\n    debug?.('[%s][%s] creating the browser page for %s', sessionId, this.browserName, url)\n    const browserPage = await this.openBrowserPage(sessionId, options)\n    debug?.('[%s][%s] browser page is created, opening %s', sessionId, this.browserName, url)\n    await browserPage.goto(url, { timeout: 0 })\n    await this._throwIfClosing(browserPage)\n  }\n\n  private async _throwIfClosing(disposable?: { close: () => Promise<void> }) {\n    if (this.closing) {\n      debug?.('[%s] provider was closed, cannot perform the action on %s', this.browserName, String(disposable))\n      await disposable?.close()\n      this.pages.clear()\n      this.contexts.clear()\n      this.browser = null\n      this.browserPromise = null\n      throw new Error(`[vitest] The provider was closed.`)\n    }\n  }\n\n  async getCDPSession(sessionid: string): Promise<CDPSession> {\n    const page = this.getPage(sessionid)\n    const cdp = await page.context().newCDPSession(page)\n    return {\n      send: cdp.send.bind(cdp),\n      on: cdp.on.bind(cdp),\n      off: cdp.off.bind(cdp),\n      once: cdp.once.bind(cdp),\n    } as any // overloaded CDPSession type is too tricky in monorepo\n  }\n\n  async close(): Promise<void> {\n    process.off('SIGTERM', this.onSIGTERM)\n\n    debug?.('[%s] closing provider', this.browserName)","sourceCodeStart":638,"sourceCodeEnd":674,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/browser-playwright/src/playwright.ts#L638-L674","documentation":"_throwIfClosing is called at multiple checkpoints (createContext, openBrowserPage, openPage) to abort work if the provider has begun closing. When this.closing is true it disposes the in-flight disposable, clears pages/contexts/browser, and throws so callers stop using a half-torn-down provider. close() sets this.closing = true during shutdown.","triggerScenarios":"Any browser operation (creating a context, opening/navigating a page) racing with provider.close() — e.g., a test still running when vitest is shutting down, SIGTERM handling, or a parallel test starting after close began.","commonSituations":"Long-running tests interrupted by SIGTERM/SIGINT or a test timeout; forceful teardown; flaky CI where the worker is killed mid-test; calling browser APIs in a hook that outlives teardown.","solutions":["Increase test timeouts if tests are being killed mid-flight, or shorten the tests so they finish before teardown.","Avoid starting new browser operations in afterAll/global teardown; the provider may already be closing.","Handle SIGTERM in your CI gracefully (do not send a second kill -9 immediately).","If reproducible, file a Vitest issue with the timing — operations should drain before close."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// you cannot reliably pre-validate a race with close(), but you can avoid it:\n// do not start browser operations in afterAll/global teardown.\n","typeGuard":null,"tryCatchPattern":"try {\n  await provider.openPage(sessionId, url, { parallel: false })\n} catch (err) {\n  if (err instanceof Error && err.message === '[vitest] The provider was closed.') {\n    // provider is shutting down; abandon the operation gracefully\n    return\n  }\n  throw err\n}","preventionTips":["Keep tests under the configured timeout so teardown does not interrupt them.","Do not issue new browser operations in afterAll/globalTeardown.","Handle SIGTERM in CI with a graceful period before SIGKILL."],"tags":["browser","playwright","lifecycle","race-condition","teardown"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}