musistudio/claude-code-router · error · Error
browser_tab_close requires tabId or session.
Error message
browser_tab_close requires tabId or session.
What it means
Thrown by the browser_tab_close MCP tool when no tab identifier can be resolved from args.tabId or an attached session. Closing requires an explicit target tab; the tool intentionally has no 'close active tab' implicit behavior.
Source
Thrown at packages/electron/src/main/browser-automation-mcp.ts:803
await this.ensureBrowserOpen();
const session = this.resolveOptionalSession(args);
const tabId = readString(args.tabId) || session?.ref.tabId;
if (!tabId) {
throw new Error("browser_tab_activate requires tabId or session.");
}
const state = builtInBrowserService.selectAutomationTab(tabId);
return {
...browserWindowState(state),
tab: summarizeTab(requiredTabState(state, tabId), state.activeTabId)
};
}
case "browser_tab_close": {
await this.ensureBrowserOpen();
const session = this.resolveOptionalSession(args);
this.assertCanMutate(session);
const tabId = readString(args.tabId) || session?.ref.tabId;
if (!tabId) {
throw new Error("browser_tab_close requires tabId or session.");
}
const state = builtInBrowserService.closeAutomationTab(tabId);
this.removeSessionsForTab(tabId);
return browserWindowState(state);
}
case "browser_navigate": {
await this.ensureBrowserOpen();
const session = this.resolveOptionalSession(args);
this.assertCanMutate(session);
const tabId = readString(args.tabId) || session?.ref.tabId || builtInBrowserService.getAutomationState().activeTabId;
if (!tabId) {
throw new Error("browser_navigate could not resolve an active tab.");
}
const url = requiredString(args.url, "browser_navigate requires url.");
const waitUntil = normalizeWaitUntil(readString(args.waitUntil), "interactive");
const readiness = await waitForReadiness(
builtInBrowserService.getAutomationWebContents(tabId),
waitUntil,View on GitHub (pinned to 99f24806c6)
Solutions
- Pass tabId explicitly in the tool arguments.
- Or pass the session ref obtained from the tool run that created the tab.
- Re-query tab state before closing to confirm the tab still exists and capture its id.
Example fix
// before
await call("browser_tab_close", {});
// after
await call("browser_tab_close", { tabId }); Defensive patterns
Strategy: validation
Validate before calling
if (!args.tabId && !args.session?.ref?.tabId) throw new Error("No tab to close — fetch state first");
await call("browser_tab_close", args); Type guard
function hasTabTarget(args: unknown): boolean { const a = args as any; return Boolean(a?.tabId ?? a?.session?.ref?.tabId); } Try / catch
try { await call("browser_tab_close", { tabId }); } catch (e) { if (e instanceof Error && e.message.includes("requires tabId or session")) { /* re-list tabs */ } throw e; } Prevention
- Track open tab ids in script state
- Tolerate already-closed tabs in cleanup loops
- Re-query after bulk operations
When it happens
Trigger: Calling tools/call with name='browser_tab_close' with empty arguments (no tabId, no session), or with a session whose ref failed to resolve.
Common situations: A script closes tabs in a loop after the tab was already closed and removed from the session map; the caller assumed the last-used tab would be implicit.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- browser_tab_activate requires tabId or session.
- A valid browser automation session is required.
- browser_chrome_login_import requires domains or an active ht
- browser_navigate could not resolve an active tab.
- Chrome login import job was not found: ${jobId}
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/48a000d7d6260770.
Report an issue: GitHub.