mastra-ai/mastra · error
browser_close requires agent.threadId when browser scope is
Error message
browser_close requires agent.threadId when browser scope is not shared
What it means
browser_close in non-shared (thread) scope closes only the calling thread's browser session, which requires knowing which thread to close. The tool reads agent.threadId; if the agent has no threadId and the browser scope is not 'shared', there is no session identity to close, so the tool throws. It prevents accidentally closing a shared browser or silently doing nothing.
Source
Thrown at browser/agent-browser/src/tools/close.ts:19
/**
* browser_close - Close the browser
*/
import { createTool } from '@mastra/core/tools';
import type { AgentBrowser } from '../agent-browser';
import { closeInputSchema } from '../schemas';
import { BROWSER_TOOLS } from './constants';
export function createCloseTool(browser: AgentBrowser) {
return createTool({
id: BROWSER_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('browser_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
- Configure the agent run so a threadId is available (enable memory/threading or pass threadId at run start).
- Switch the browser tooling to shared scope so no per-thread identity is required.
- Skip browser_close when threadId is absent and rely on TTL/idle session cleanup.
- Catch the error and return structured guidance to the model to provide thread context.
Example fix
// before
await closeTool.execute({}, { agent: {} }); // throws: no threadId
// after
await closeTool.execute({}, { agent: { threadId: 'thread-123' } });
// or use shared scope
const tools = createAgentBrowserTools({ scope: 'shared' }); Defensive patterns
Strategy: validation
Validate before calling
if (!agent?.threadId && browser.getScope() !== 'shared') {
throw new Error('Cannot close browser: agent.threadId is required for non-shared scope');
}
await closeTool.execute({}, { agent }); 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 closeTool.execute({}, { agent });
} catch (err) {
if (err instanceof Error && err.message.includes('requires agent.threadId')) {
return { success: false, reason: 'missing-thread-context' };
}
throw err;
} Prevention
- Always run agents with memory/threading enabled when using thread-scoped browser tools.
- Assert agent.threadId exists in your runner before invoking browser tools.
- Prefer shared scope when thread isolation is not needed.
- Catch this error and return actionable guidance instead of a raw failure.
When it happens
Trigger: Calling the browser_close tool from an agent run where agent.threadId is undefined (agent invoked without thread/memory context) while browser scope is any value other than 'shared'.
Common situations: Running an agent without memory/threading configured; custom runners that don't populate agent.threadId; tests or scripts invoking the tool's execute directly without an agent context.
Related errors
- Unsupported browser provider: ${provider}
- Invalid browser configuration: "cdpUrl" and "scope: 'thread'
- Invalid browser configuration: "cdpUrl" cannot be used with
- Subconscious remind requires organizationId in the request c
- Subconscious remind requires a resourceId.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/42fcd0c97a62e95e.
Report an issue: GitHub.