{"record":{"id":"34b7e7861480d66b","repo":"CherryHQ/cherry-studio","slug":"tab-newtabid-was-created-but-not-found-it-may","errorCode":null,"errorMessage":"Tab ${newTabId} was created but not found - it may have been closed","messagePattern":"Tab (.+?) was created but not found - it may have been closed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/servers/browser/controller.ts","lineNumber":596,"sourceCode":"        this.touchTab(windowInfo.windowKey, tabId)\n        return { tabId, tab }\n      }\n    }\n\n    // Use active tab or create new one\n    if (windowInfo.activeTabId) {\n      const activeTab = windowInfo.tabs.get(windowInfo.activeTabId)\n      if (activeTab && !activeTab.view.webContents.isDestroyed()) {\n        this.touchTab(windowInfo.windowKey, windowInfo.activeTabId)\n        return { tabId: windowInfo.activeTabId, tab: activeTab }\n      }\n    }\n\n    // Create new tab\n    const { tabId: newTabId } = await this.createTab(privateMode, showWindow)\n    const tab = windowInfo.tabs.get(newTabId)\n    if (!tab) {\n      throw new Error(`Tab ${newTabId} was created but not found - it may have been closed`)\n    }\n    return { tabId: newTabId, tab }\n  }\n\n  /**\n   * Opens a URL in a browser window and waits for navigation to complete.\n   * @param url - The URL to navigate to\n   * @param timeout - Navigation timeout in milliseconds (default: 10000)\n   * @param privateMode - If true, uses private browsing mode (default: false)\n   * @param newTab - If true, always creates a new tab (useful for parallel requests)\n   * @param showWindow - If true, shows the browser window (default: false)\n   * @returns Object containing the current URL, page title, and tab ID after navigation\n   */\n  public async open(url: string, timeout = 10000, privateMode = false, newTab = false, showWindow = false) {\n    // Reject non-http(s) schemes (e.g. file://) and local/private hosts before navigating\n    // (covers fetch() too, which routes through open()) to prevent local-file read / SSRF.\n    url = sanitizeRemoteUrl(url)\n","sourceCodeStart":578,"sourceCodeEnd":614,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/browser/controller.ts#L578-L614","documentation":"Same creation race as error 249 but in the fallback branch of getActiveOrCreateTab: when there is no usable active tab and no supplied tabId, the code calls createTab then immediately looks up the new tabId in windowInfo.tabs. If webContents 'destroyed' has already deleted it, the lookup fails.","triggerScenarios":"The first/only tab in a window is created and its webContents is destroyed before the creating call returns — e.g. app shutting down, GPU process crash, sandbox init failure, or a concurrent dispose.","commonSituations":"First navigation request hitting browser tool during shutdown; Electron failing to spawn the render process for the new tab; concurrent closeTab/dispose racing the implicit 'create first tab' path.","solutions":["Retry createTab once, and if it still fails, surface a deterministic 'unable to create browser tab' error.","Add an isDisposing guard so requests during teardown short-circuit instead of racing destruction.","Check Electron logs for render-process/GPU crashes on BrowserView construction.","Ensure getOrCreateWindow has fully settled (await ensureAppReady) before creating tabs."],"exampleFix":"// before\nconst { tabId: newTabId } = await this.createTab(privateMode, showWindow)\nconst tab = windowInfo.tabs.get(newTabId)\nif (!tab) {\n  throw new Error(`Tab ${newTabId} was created but not found - it may have been closed`)\n}\n\n// after — single retry + teardown guard\nlet created = await this.createTab(privateMode, showWindow)\nlet tab = windowInfo.tabs.get(created.tabId)\nif (!tab && !this.disposing) {\n  created = await this.createTab(privateMode, showWindow)\n  tab = windowInfo.tabs.get(created.tabId)\n}\nif (!tab) throw new Error('Unable to create browser tab (webContents destroyed)')\nreturn { tabId: created.tabId, tab }","handlingStrategy":"try-catch","validationCode":"async function ensureActiveTab(controller, windowInfo, privateMode, showWindow) {\n  let created = await controller.createTab(privateMode, showWindow)\n  let tab = windowInfo.tabs.get(created.tabId)\n  if (!tab && !controller.disposing) {\n    created = await controller.createTab(privateMode, showWindow)\n    tab = windowInfo.tabs.get(created.tabId)\n  }\n  if (!tab) throw new Error('unable to create a usable browser tab')\n  return { tabId: created.tabId, tab }\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await ensureActiveTab(controller, windowInfo, privateMode, showWindow)\n} catch (e) {\n  if (controller.disposing) throw new Error('browser controller shutting down')\n  throw e\n}","preventionTips":["Ensure ensureAppReady has settled before creating tabs.","Stop issuing browser calls once disposal begins.","Monitor for render-process crashes that destroy new views instantly."],"tags":["electron","browser-tool","race","tabs","webcontents"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}