{"record":{"id":"efdb9b75a3710ff9","repo":"mastra-ai/mastra","slug":"createstagehand-factory-not-set-required-for-thr","errorCode":null,"errorMessage":"createStagehand factory not set - required for thread scope","messagePattern":"createStagehand factory not set - required for thread scope","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"browser/stagehand/src/thread-manager.ts","lineNumber":88,"sourceCode":"  }\n\n  /**\n   * Create a new session for a thread.\n   */\n  protected override async createSession(threadId: string): Promise<StagehandThreadSession> {\n    // Check for saved browser state before creating new session (for browser restore)\n    const savedState = this.getSavedBrowserState(threadId);\n\n    const session: StagehandThreadSession = {\n      threadId,\n      createdAt: Date.now(),\n      browserState: savedState,\n    };\n\n    if (this.scope === 'thread') {\n      // Full thread scope - create a new Stagehand instance\n      if (!this.createStagehand) {\n        throw new Error('createStagehand factory not set - required for thread scope');\n      }\n\n      this.logger?.debug?.(`Creating dedicated Stagehand instance for thread ${threadId}`);\n      const stagehand = await this.createStagehand();\n      session.stagehand = stagehand;\n      this.threadManagers.set(threadId, stagehand);\n\n      // Restore browser state if available (before notifying parent to avoid screencast race)\n      if (savedState && savedState.tabs.length > 0) {\n        this.logger?.debug?.(`Restoring browser state for thread ${threadId}: ${savedState.tabs.length} tabs`);\n        await this.restoreBrowserState(stagehand, savedState);\n      }\n\n      // Notify parent browser so it can set up close listeners\n      // This is done after restoration so the screencast starts on the correct active page\n      this.onBrowserCreated?.(stagehand, threadId);\n    }\n    // For 'shared' scope, no session setup needed - all threads share the instance","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/browser/stagehand/src/thread-manager.ts#L70-L106","documentation":"In 'thread' scope, the StagehandThreadManager creates a dedicated Stagehand instance per thread by invoking an injected createStagehand factory. If that factory was never provided at construction, the manager cannot fulfill thread-scoped session creation and throws. This is a configuration/dependency-injection error, not a runtime browser problem.","triggerScenarios":"Calling createSession with scope='thread' on a StagehandBrowser whose thread manager was constructed without a createStagehand callback.","commonSituations":"Constructing the browser/thread manager manually without wiring the factory; copying setup code that assumed shared scope but switching to thread scope; library version upgrades requiring the factory for thread scope; DI container not providing the factory.","solutions":["Pass a createStagehand factory when constructing StagehandBrowser / the thread manager","Ensure your constructor config actually enables thread scope intentionally and supplies the factory","Update wiring code after library upgrades that made the factory required for thread scope","Fall back to shared scope if per-thread instances are not needed"],"exampleFix":"// before\nconst browser = new StagehandBrowser({ scope: 'thread' });\n// after\nconst browser = new StagehandBrowser({\n  scope: 'thread',\n  threadManagerOptions: {\n    createStagehand: async () => new Stagehand({ env: 'LOCAL', ... }),\n  },\n});","handlingStrategy":"validation","validationCode":"if (!threadManager.createStagehand) {\n  throw new Error('thread scope requires a createStagehand factory at construction');\n}","typeGuard":"function supportsThreadScope(m: { scope: string; createStagehand?: unknown }):\n  m is { scope: 'thread'; createStagehand: () => Promise<Stagehand> } {\n  return m.scope === 'thread' && typeof m.createStagehand === 'function';\n}","tryCatchPattern":"try {\n  await threadManager.createSession(threadId);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('createStagehand factory not set')) {\n    throw new Error('Misconfiguration: wire createStagehand when scope=thread');\n  }\n  throw e;\n}","preventionTips":["Always supply createStagehand when constructing a thread-scoped manager","Type the options so scope='thread' requires the factory (discriminated union)","Add a construction-time assertion if scope is dynamic","Review wiring after upgrades that change thread-scope requirements"],"tags":["config","dependency-injection","stagehand","thread-scope"],"backgroundTag":"missing-factory-callback","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}