{"record":{"id":"51811b4536c7c576","repo":"CherryHQ/cherry-studio","slug":"tab-tabid-not-found","errorCode":null,"errorMessage":"Tab ${tabId} not found","messagePattern":"Tab (.+?) not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/servers/browser/controller.ts","lineNumber":931,"sourceCode":"   * @param privateMode - If true, closes tab from private window (default: false)\n   * @param tabId - Tab identifier to close\n   */\n  public async closeTab(privateMode: boolean, tabId: string) {\n    await this.reset(privateMode, tabId)\n  }\n\n  /**\n   * Switches the active tab\n   * @param privateMode - If true, switches tab in private window (default: false)\n   * @param tabId - Tab identifier to switch to\n   */\n  public async switchTab(privateMode: boolean, tabId: string) {\n    const windowKey = this.getWindowKey(privateMode)\n    const windowInfo = this.windows.get(windowKey)\n    if (!windowInfo) throw new Error(`Window not found for ${privateMode ? 'private' : 'normal'} mode`)\n\n    const tab = windowInfo.tabs.get(tabId)\n    if (!tab) throw new Error(`Tab ${tabId} not found`)\n\n    // Remove previous active tab view (but NOT the tabBarView)\n    if (windowInfo.activeTabId && windowInfo.activeTabId !== tabId) {\n      const prevTab = windowInfo.tabs.get(windowInfo.activeTabId)\n      if (prevTab && !windowInfo.window.isDestroyed()) {\n        windowInfo.window.removeBrowserView(prevTab.view)\n      }\n    }\n\n    windowInfo.activeTabId = tabId\n\n    // Add the new active tab view\n    if (!windowInfo.window.isDestroyed()) {\n      windowInfo.window.addBrowserView(tab.view)\n      this.updateViewBounds(windowInfo)\n    }\n\n    this.touchTab(windowKey, tabId)","sourceCodeStart":913,"sourceCodeEnd":949,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/browser/controller.ts#L913-L949","documentation":"After resolving a window for the mode, switchTab looks up windowInfo.tabs.get(tabId); if absent it throws 'Tab ${tabId} not found'. The tab may have been closed (webContents 'destroyed' deletes the entry) or the tabId was never created in that window.","triggerScenarios":"Agent passes a tabId from a different window/mode; the tab was already closed via closeTab/closeTabInternal; the webContents 'destroyed' event removed it; or a stale tabId cached by the agent.","commonSituations":"Agent holds an old tabId across a reset/close; mode mismatch (normal-mode tabId used in private mode); tab crashed and auto-removed; concurrent closeTab raced switchTab.","solutions":["Validate the tabId against the window's current tabs before calling switchTab; re-enumerate if stale.","Ensure the privateMode flag matches the mode the tabId was created under.","Handle 'tab not found' by falling back to the active tab or creating a fresh one.","Avoid caching tabIds long-term; re-query the controller's list_tabs."],"exampleFix":"// before\nconst tab = windowInfo.tabs.get(tabId)\nif (!tab) throw new Error(`Tab ${tabId} not found`)\n\n// after — fall back to active tab or create one\nlet tab = windowInfo.tabs.get(tabId)\nif (!tab) {\n  if (windowInfo.activeTabId) {\n    tab = windowInfo.tabs.get(windowInfo.activeTabId)\n  }\n  if (!tab) {\n    const created = await this.createTab(privateMode, false)\n    tab = windowInfo.tabs.get(created.tabId)\n  }\n  if (!tab) throw new Error(`Tab ${tabId} not found and no fallback available`)\n}","handlingStrategy":"validation","validationCode":"// Verify the tabId is live in the target window before switching\nfunction tabExists(controller, privateMode, tabId) {\n  const windowKey = controller.getWindowKey(privateMode)\n  const windowInfo = controller.windows.get(windowKey)\n  return !!windowInfo && windowInfo.tabs.has(tabId) && !windowInfo.tabs.get(tabId).view.webContents.isDestroyed()\n}","typeGuard":"function isLiveTab(windowInfo, tabId): boolean {\n  const t = windowInfo?.tabs?.get(tabId)\n  return !!t && !t.view.webContents.isDestroyed()\n}","tryCatchPattern":"if (!tabExists(controller, privateMode, tabId)) {\n  return { content: [{ type: 'text', text: `Tab ${tabId} no longer exists` }], isError: true }\n}","preventionTips":["Do not cache tabIds long-term; re-enumerate via list_tabs.","Match privateMode to the tab's originating window.","Fall back to the active tab when the requested one is gone."],"tags":["electron","browser-tool","tabs","validation"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}