{"record":{"id":"42fcd0c97a62e95e","repo":"mastra-ai/mastra","slug":"browser-close-requires-agent-threadid-when-browser","errorCode":null,"errorMessage":"browser_close requires agent.threadId when browser scope is not shared","messagePattern":"browser_close requires agent\\.threadId when browser scope is not shared","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"browser/agent-browser/src/tools/close.ts","lineNumber":19,"sourceCode":"/**\n * browser_close - Close the browser\n */\nimport { createTool } from '@mastra/core/tools';\nimport type { AgentBrowser } from '../agent-browser';\nimport { closeInputSchema } from '../schemas';\nimport { BROWSER_TOOLS } from './constants';\nexport function createCloseTool(browser: AgentBrowser) {\n  return createTool({\n    id: BROWSER_TOOLS.CLOSE,\n    description: 'Close the browser. Only use when done with all browsing.',\n    inputSchema: closeInputSchema,\n    execute: async (_input, { agent }) => {\n      // For thread scope, close only the thread's session\n      const threadId = agent?.threadId;\n      browser.setCurrentThread(threadId);\n      if (browser.getScope() !== 'shared') {\n        if (!threadId) {\n          throw new Error('browser_close requires agent.threadId when browser scope is not shared');\n        }\n        browser.markBrowserCloseReason('agent', threadId);\n        await browser.closeThreadSession(threadId);\n        return { success: true, hint: \"Thread's browser session closed. A new session will be created on next use.\" };\n      }\n      // For shared scope, close the entire browser\n      browser.markBrowserCloseReason('agent');\n      await browser.close();\n      return { success: true, hint: 'Browser closed. It will be re-launched automatically on next use.' };\n    },\n  });\n}\n","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/browser/agent-browser/src/tools/close.ts#L1-L32","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","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."],"exampleFix":"// before\nawait closeTool.execute({}, { agent: {} }); // throws: no threadId\n// after\nawait closeTool.execute({}, { agent: { threadId: 'thread-123' } });\n// or use shared scope\nconst tools = createAgentBrowserTools({ scope: 'shared' });","handlingStrategy":"validation","validationCode":"if (!agent?.threadId && browser.getScope() !== 'shared') {\n  throw new Error('Cannot close browser: agent.threadId is required for non-shared scope');\n}\nawait closeTool.execute({}, { agent });","typeGuard":"function hasThreadContext(agent: unknown): agent is { threadId: string } {\n  return typeof agent === 'object' && agent !== null &&\n    'threadId' in agent && typeof (agent as { threadId?: unknown }).threadId === 'string' &&\n    (agent as { threadId: string }).threadId.length > 0;\n}","tryCatchPattern":"try {\n  await closeTool.execute({}, { agent });\n} catch (err) {\n  if (err instanceof Error && err.message.includes('requires agent.threadId')) {\n    return { success: false, reason: 'missing-thread-context' };\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["browser","thread-scope","missing-context","configuration"],"backgroundTag":"missing-thread-context","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}