{"record":{"id":"7f276cd57f738d67","repo":"mastra-ai/mastra","slug":"cannot-launch-browser-in-this-status-state","errorCode":null,"errorMessage":"Cannot launch browser in '${this.status}' state","messagePattern":"Cannot launch browser in '(.+?)' state","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/browser/browser.ts","lineNumber":710,"sourceCode":"  async launch(threadId?: string): Promise<void> {\n    // Set current thread if provided, so thread-scoped browsers launch for that thread\n    if (threadId !== undefined) {\n      this.setCurrentThread(threadId);\n    }\n\n    // Already ready\n    if (this.status === 'ready') {\n      return;\n    }\n\n    // Already launching - wait for existing promise\n    if (this.status === 'launching' && this._launchPromise) {\n      return this._launchPromise;\n    }\n\n    // Can't launch if closing/closed\n    if (this.status === 'closing' || this.status === 'closed') {\n      throw new Error(`Cannot launch browser in '${this.status}' state`);\n    }\n\n    this.status = 'launching';\n    this.error = undefined;\n\n    this._launchPromise = (async () => {\n      try {\n        await this.doLaunch();\n        this.status = 'ready';\n\n        // Fire onLaunch hook\n        if (this.config.onLaunch) {\n          await this.config.onLaunch({ browser: this });\n        }\n\n        // Notify onBrowserReady callbacks\n        this.notifyBrowserReady();\n      } catch (err) {","sourceCodeStart":692,"sourceCodeEnd":728,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/browser/browser.ts#L692-L728","documentation":"MastraBrowser.launch() enforces a lifecycle state machine. If the browser instance is currently 'closing' or already 'closed', launch() refuses to start a new browser process and throws. A browser can only transition to 'launching' from 'pending' (or be awaited via an existing _launchPromise when already 'launching').","triggerScenarios":"Calling launch() (directly or via ensureReady) on a browser instance on which close()/closeSession has been called, or while a close is still in flight; calling launch() twice concurrently on the same instance after it was closed without resetting status to 'pending'.","commonSituations":"A long-lived browser object is closed by the app (or by a thread-session timeout) but reused later without recreating the instance; a race where one part of the app closes the browser while an agent request triggers ensureReady; calling connect after disconnecting.","solutions":["Recreate the browser instance (new Browser(...)) instead of reusing a closed one.","Call ensureReady() rather than launch() directly — it re-launches browsers that were previously closed.","Serialize lifecycle: await all close()/in-flight close promises before issuing a new launch.","Check this.status (or expose a helper) before calling launch()."],"exampleFix":"// before\nawait browser.close();\nawait browser.launch(); // throws\n// after\nawait browser.close();\nbrowser = new PlaywrightBrowser({ ...opts }); // or call ensureReady()\nawait browser.ensureReady();","handlingStrategy":"try-catch","validationCode":"// guard before launching\nif (browser.status === 'closing' || browser.status === 'closed') {\n  throw new Error(`Refusing to launch: browser is ${browser.status}; recreate the instance`);\n}\nawait browser.launch();","typeGuard":"function canLaunch(b: { status: string }): b is { status: 'pending' | 'launching' } {\n  return b.status === 'pending' || b.status === 'launching';\n}","tryCatchPattern":"try {\n  await browser.ensureReady();\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Cannot launch browser in '\")) {\n    browser = createBrowser(options); // recreate on closed/closing state\n    await browser.ensureReady();\n  } else throw err;\n}","preventionTips":["Prefer ensureReady() over raw launch() — it handles closed browsers.","Treat browser instances as single-use across close(): recreate after close.","Serialize lifecycle calls; never fire close() and launch() concurrently.","Log status transitions in custom providers to spot stale states."],"tags":["browser-lifecycle","state-machine","race-condition"],"backgroundTag":"browser-invalid-state","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}