musistudio/claude-code-router · error · Error

Browser automation session tab was not found: ${ref.tabId}

Error message

Browser automation session tab was not found: ${ref.tabId}

What it means

Thrown when restoring an unknown session (not in the in-memory sessions map) whose referenced tabId no longer exists in the browser automation state. Session restore requires the target tab to still be live; a dead tab means the session cannot be rehydrated.

Source

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

    }
    return session;
  }

  private resolveOptionalSession(args: Record<string, unknown>): AttachedSession | undefined {
    const ref = readSessionRef(args.session);
    if (!ref) {
      return undefined;
    }
    const existing = this.sessions.get(ref.sessionId);
    if (existing) {
      if (existing.ref.tabId !== ref.tabId) {
        throw new Error("Browser automation session tabId does not match the attached session.");
      }
      return existing;
    }
    const state = builtInBrowserService.getAutomationState();
    if (!state.tabs.some((tab) => tab.id === ref.tabId)) {
      throw new Error(`Browser automation session tab was not found: ${ref.tabId}`);
    }
    const restored: AttachedSession = {
      attachedAt: Date.now(),
      leaseId: randomUUID(),
      observeOnly: false,
      ref
    };
    this.sessions.set(ref.sessionId, restored);
    return restored;
  }

  private assertCanMutate(session?: AttachedSession): void {
    if (session?.observeOnly) {
      throw new Error("This browser automation session is observeOnly and cannot mutate browser state.");
    }
  }

  private removeSessionsForTab(tabId: string): void {

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Re-attach to a live tab and use the newly returned session object.
  2. Avoid closing a tab while you still intend to use its session.
  3. Treat this as a signal to re-discover state (browser_tab_list) rather than retrying the same ref.

Example fix

// before
await call("browser_tab_close", { tabId });
await call("browser_tool", { session: oldSession });

// after
await call("browser_tab_close", { tabId });
const { session } = await call("browser_attach", { tabId: newTabId });
await call("browser_tool", { session });
Defensive patterns

Strategy: fallback

Validate before calling

const { tabs } = await call("browser_tab_list", {});
if (!tabs.some((t) => t.id === session.ref.tabId)) { const { session: s } = await call("browser_attach", { tabId: tabs[0].id }); session = s; }
await call(tool, { session });

Try / catch

try { await call(tool, { session }); } catch (e) { if (e instanceof Error && e.message.includes("session tab was not found")) { const { session: s } = await call("browser_attach", { tabId }); await call(tool, { session: s }); } else throw e; }

Prevention

When it happens

Trigger: Passing a session ref whose tab was closed (closing a tab removes its sessions, so the ref is treated as new), or after the automation browser reopened with fresh tabs while the caller kept an old ref.

Common situations: Long-running scripts that pause and resume; app/browser restart invalidating tab ids; closing a tab mid-workflow and reusing the prior session object in the next call.

Related errors


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