mastra-ai/mastra · error
Browser not launched
Error message
Browser not launched
What it means
requireStagehand resolves the Stagehand instance for the current thread, falling back to the shared manager. If neither a thread-scoped manager nor a shared manager exists, no browser was ever launched, so any Stagehand-dependent operation cannot proceed and the library throws. It is a guard ensuring you cannot interact with a browser that does not exist.
Source
Thrown at browser/stagehand/src/stagehand-browser.ts:458
await this.threadManager.getManagerForThread(threadId);
stagehand = this.threadManager.getExistingManagerForThread(threadId);
}
return stagehand ?? null;
}
/**
* Require a Stagehand instance for the given or current thread.
* Throws if no instance is available.
* @param explicitThreadId - Optional thread ID to use instead of getCurrentThread()
* Use this to avoid race conditions in concurrent tool calls.
*/
private requireStagehand(explicitThreadId?: string): Stagehand {
const threadId = explicitThreadId ?? this.getCurrentThread();
const stagehand = this.threadManager.getExistingManagerForThread(threadId) ?? this.sharedManager;
if (!stagehand) {
throw new Error('Browser not launched');
}
return stagehand;
}
/**
* Get the current page from Stagehand v3, respecting thread scope.
* @param explicitThreadId - Optional thread ID to use instead of getCurrentThread()
* Use this to avoid race conditions in concurrent tool calls.
*/
private getPage(explicitThreadId?: string): V3Page | null {
const scope = this.getScope();
const threadId = explicitThreadId ?? this.getCurrentThread();
// For 'thread' scope, get the thread's Stagehand's active page
if (scope === 'thread' && threadId && threadId !== DEFAULT_THREAD_ID) {
const stagehand = this.threadManager.getExistingManagerForThread(threadId);
if (stagehand?.context) {
return stagehand.context.activePage() as V3Page | null;View on GitHub (pinned to 75dd419e61)
Solutions
- Call launch()/connect() on the StagehandBrowser before using it
- Check that prior launch did not fail (it throws its own error) and that no early close() ran
- If using thread scope, operate from a thread that has an active session or rely on the shared manager
- Verify initialization order in your app lifecycle (e.g. launch in startup hook)
Example fix
// before const page = await browser.stagehand().page; // after await browser.launch(); const page = await browser.stagehand().page;
Defensive patterns
Strategy: try-catch
Validate before calling
if (!browser.isBrowserRunning()) {
await browser.launch();
} Try / catch
try {
const stagehand = browser.stagehand();
} catch (e) {
if (e instanceof Error && e.message === 'Browser not launched') {
await browser.launch();
} else throw e;
} Prevention
- Launch the browser in an awaited startup path before any usage
- Check isBrowserRunning() before operations after long idle periods
- Ensure close()/disconnect() is not called while operations are pending
- Track browser lifecycle in a central manager, not ad-hoc call sites
When it happens
Trigger: Calling the public stagehand accessor (or methods that route through requireStagehand, like getPage/actions) before calling launch/connect, or after the browser was closed such that no manager remains.
Common situations: Forgetting to await browser launch at startup; calling the browser from a different thread scope where only thread-scoped sessions exist; using a StagehandBrowser after close()/disconnect; race where launch failed silently upstream.
Related errors
- Shared browser not launched. Call createSharedSession() firs
- SlackProvider not attached to Mastra. Call __attach() first.
- GithubIntegration storage has not been initialized.
- GithubIntegration source-control storage has not been initia
- IssueReconcileWorker: call init() before start()
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/6c7100aa6c4039c6.
Report an issue: GitHub.