mastra-ai/mastra · error
stagehand_close requires agent.threadId when browser scope i
Error message
stagehand_close requires agent.threadId when browser scope is not shared
What it means
stagehand_close closes browser sessions for the current thread. When the browser scope is not 'shared' (i.e. per-thread sessions), the tool needs to know which thread's session to close, and derives it from agent.threadId. If threadId is missing the tool cannot identify a session to close, so it throws rather than silently closing the wrong session.
Source
Thrown at browser/stagehand/src/tools/close.ts:21
*/
import { createTool } from '@mastra/core/tools';
import { closeInputSchema } from '../schemas';
import type { StagehandBrowser } from '../stagehand-browser';
import { STAGEHAND_TOOLS } from './constants';
export function createCloseTool(browser: StagehandBrowser) {
return createTool({
id: STAGEHAND_TOOLS.CLOSE,
description: 'Close the browser. Only use when done with all browsing.',
inputSchema: closeInputSchema,
execute: async (_input, { agent }) => {
// For thread scope, close only the thread's session
const threadId = agent?.threadId;
browser.setCurrentThread(threadId);
if (browser.getScope() !== 'shared') {
if (!threadId) {
throw new Error('stagehand_close requires agent.threadId when browser scope is not shared');
}
browser.markBrowserCloseReason('agent', threadId);
await browser.closeThreadSession(threadId);
return {
success: true,
hint: "Thread's browser session closed. A new session will be created on next use.",
};
}
// For shared scope, close the entire browser
browser.markBrowserCloseReason('agent');
await browser.close();
return {
success: true,
hint: 'Browser closed. It will be re-launched automatically on next use.',
};
},
});
}View on GitHub (pinned to 75dd419e61)
Solutions
- Run the agent within a thread so agent.threadId is populated (enable memory / pass threadId in the run options)
- Switch browser scope to 'shared' if all agents should share one browser session, removing the threadId requirement
- Ensure the tool is invoked through the standard agent execution path (createStagehandTools wired into the agent) rather than called directly without an agent context
Example fix
// before
const tools = createStagehandTools({ scope: 'thread' });
await agent.generate(prompt); // no threadId -> error on stagehand_close
// after
await memory.createThread({ resourceId, threadId });
await agent.generate(prompt, { memory: { thread: threadId, resource: resourceId } }); Defensive patterns
Strategy: validation
Validate before calling
if (scope !== 'shared' && !agent?.threadId) {
throw new Error('stagehand_close needs a thread: run the agent inside a thread or use scope "shared"');
} Type guard
function hasThreadContext(agent: unknown): agent is { threadId: string } {
return typeof agent === 'object' && agent !== null && 'threadId' in agent && typeof (agent as { threadId?: unknown }).threadId === 'string' && (agent as { threadId: string }).threadId.length > 0;
} Try / catch
try {
await stagehandCloseTool.execute({}, { agent });
} catch (e) {
if ((e as Error).message.includes('requires agent.threadId')) {
// fall back to shared scope or re-run within a thread context
} else throw e;
} Prevention
- Always run thread-scoped agents with memory/thread context enabled
- Assert agent.threadId exists before invoking thread-scoped tools
- Prefer 'shared' scope if your harness is threadless
When it happens
Trigger: Calling the stagehand_close tool (via createCloseTool, exported by createStagehandTools) with browser scope set to 'thread' or another non-shared scope while the executing agent has no threadId (e.g. run outside a thread/memory context, or tool invoked without an agent context).
Common situations: Running a Stagehand-enabled agent with memory disabled or threadless execution; invoking tools via a custom runner that does not propagate the thread context; misconfigured scope ('thread') combined with a harness that drops agent metadata.
Related errors
- browser_close requires agent.threadId when browser scope is
- No browser context available for screencast
- CDP session not available for mouse injection
- CDP session not available for keyboard injection
- Shared browser not launched. Call createSharedSession() firs
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7680aeb54048a48a.
Report an issue: GitHub.