{"record":{"id":"4862b808c2c4acfa","repo":"mastra-ai/mastra","slug":"browser-is-this-status-and-cannot-be-used","errorCode":null,"errorMessage":"Browser is ${this.status} and cannot be used","messagePattern":"Browser is (.+?) and cannot be used","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/browser/browser.ts","lineNumber":861,"sourceCode":"      // Reset to pending to allow re-launch after close\n      if (this.status === 'closed') {\n        this.status = 'pending';\n      }\n      await this.launch();\n      return;\n    }\n    if (this.status === 'launching') {\n      await this._launchPromise;\n      return;\n    }\n    if (this.status === 'closing') {\n      // Wait for close to complete, then re-launch\n      await this._closePromise;\n      this.status = 'pending';\n      await this.launch();\n      return;\n    }\n    throw new Error(`Browser is ${this.status} and cannot be used`);\n  }\n\n  /**\n   * Check if the browser is still alive.\n   * Override in subclass to detect externally closed browsers.\n   * @returns true if browser is alive, false if it was externally closed\n   */\n  protected async checkBrowserAlive(): Promise<boolean> {\n    // Default implementation assumes browser is alive if status is ready\n    return true;\n  }\n\n  /**\n   * Check if the browser is currently running.\n   * @param _threadId - Thread identifier (for thread-scoped browsers)\n   */\n  isBrowserRunning(_threadId?: string): boolean {\n    return this.status === 'ready';","sourceCodeStart":843,"sourceCodeEnd":879,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/browser/browser.ts#L843-L879","documentation":"ensureReady() verifies the browser is usable before delegating to launch(). It recovers from 'pending' and from a completed close (re-launches), but if the status is anything else it cannot handle — typically 'launching' without a tracked launch promise, or another unrecoverable state — it throws with the current status in the message.","triggerScenarios":"Calling an operation that goes through ensureReady() while the browser is in an intermediate/unexpected status (e.g. status set to 'launching' by another code path, or a custom provider subclass mutating this.status manually and leaving it in a non-standard state).","commonSituations":"Custom provider subclasses that manage this.status themselves and leave stale values; concurrent lifecycle calls where status was set but the launch promise was cleared; corrupted state after a partially failed close/re-launch cycle.","solutions":["Log/inspect this.status at the throw site and reset it to 'pending' before retrying.","Avoid manually mutating this.status in provider subclasses; use the base-class lifecycle methods.","Recreate the browser instance if its state is unrecoverable.","Add lifecycle locking so only launch()/close() change status."],"exampleFix":"// before (custom provider)\nthis.status = 'launching'; // manual mutation, promise not tracked\n// after\nawait this.launch(); // base class sets status and tracks _launchPromise","handlingStrategy":"retry","validationCode":"// only proceed on known-good states\nconst usable = ['pending', 'ready', 'closed'];\nif (!usable.includes(browser.status)) {\n  throw new Error(`Unexpected browser status ${browser.status}; aborting operation`);\n}\nawait browser.ensureReady();","typeGuard":"function isUsableStatus(s: string): boolean {\n  return ['pending', 'ready', 'closed'].includes(s);\n}","tryCatchPattern":"try {\n  await browser.ensureReady();\n} catch (err) {\n  if (err instanceof Error && /^Browser is .+ and cannot be used$/.test(err.message)) {\n    // state machine corrupted: recreate instead of retrying same instance\n    browser = createBrowser(options);\n    await browser.ensureReady();\n  } else throw err;\n}","preventionTips":["Never mutate this.status from outside the base-class lifecycle methods.","Route all browser use through ensureReady(), not direct method calls.","Add a mutex/queue around launch/close to keep status transitions atomic.","Alert on unknown status values in logs."],"tags":["browser-lifecycle","state-machine","concurrency"],"backgroundTag":"browser-invalid-state","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}