musistudio/claude-code-router · error · Error

browser_tab_activate requires tabId or session.

Error message

browser_tab_activate requires tabId or session.

What it means

Thrown by the browser_tab_activate MCP tool when neither args.tabId nor an attached session provides a tab identifier, and no fallback resolves. Tab activation is inherently tab-specific, so unlike browser_navigate there is no implicit 'active tab' fallback here.

Source

Thrown at packages/electron/src/main/browser-automation-mcp.ts:789

  }

  private async runTool(name: string, args: Record<string, unknown>): Promise<unknown> {
    switch (name) {
      case "browser_session_open":
        return await this.openSession(args);
      case "browser_session_close":
        return this.closeSession(args);
      case "browser_tab_create":
        return await this.createTab(args);
      case "browser_tab_list":
        await this.ensureBrowserOpen();
        return browserWindowState();
      case "browser_tab_activate": {
        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);

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Include tabId in the tool arguments, sourced from a prior browser_open/browser_tab_list result.
  2. Or pass the session object returned by a previous attach/connect tool call so its ref.tabId is used.
  3. List tabs first (browser_tab_list) and pick a concrete id instead of relying on an implicit active tab.

Example fix

// before
await call("browser_tab_activate", {});

// after
const tabs = await call("browser_tab_list", {});
await call("browser_tab_activate", { tabId: tabs.tabs[0].id });
Defensive patterns

Strategy: validation

Validate before calling

const hasTarget = Boolean(readString(args.tabId) || args.session?.ref?.tabId);
if (!hasTarget) { const { tabs } = await call("browser_tab_list", {}); args.tabId = tabs[0]?.id; }
await call("browser_tab_activate", args);

Type guard

function hasTabTarget(args: unknown): args is { tabId: string } | { session: { ref: { tabId: string } } } { const a = args as any; return typeof a?.tabId === "string" && a.tabId.trim() !== "" || typeof a?.session?.ref?.tabId === "string"; }

Try / catch

try { await call("browser_tab_activate", args); } catch (e) { if (e instanceof Error && e.message.includes("requires tabId or session")) { /* fetch tabs and retry with explicit tabId */ } throw e; }

Prevention

When it happens

Trigger: Calling tools/call with name='browser_tab_activate' and arguments containing neither tabId nor a valid session ref, after the browser has opened.

Common situations: The caller assumes the tool will target the currently active tab; the session object passed is malformed or references an expired session so session.ref.tabId is undefined.

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


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/366526319f356c5d. Report an issue: GitHub.