CherryHQ/cherry-studio · error · Error

Tab ${newTabId} was created but not found - it may have been

Error message

Tab ${newTabId} was created but not found - it may have been closed

What it means

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.

Source

Thrown at src/main/ai/mcp/servers/browser/controller.ts:596

        this.touchTab(windowInfo.windowKey, tabId)
        return { tabId, tab }
      }
    }

    // Use active tab or create new one
    if (windowInfo.activeTabId) {
      const activeTab = windowInfo.tabs.get(windowInfo.activeTabId)
      if (activeTab && !activeTab.view.webContents.isDestroyed()) {
        this.touchTab(windowInfo.windowKey, windowInfo.activeTabId)
        return { tabId: windowInfo.activeTabId, tab: activeTab }
      }
    }

    // Create new tab
    const { tabId: newTabId } = await this.createTab(privateMode, showWindow)
    const tab = windowInfo.tabs.get(newTabId)
    if (!tab) {
      throw new Error(`Tab ${newTabId} was created but not found - it may have been closed`)
    }
    return { tabId: newTabId, tab }
  }

  /**
   * Opens a URL in a browser window and waits for navigation to complete.
   * @param url - The URL to navigate to
   * @param timeout - Navigation timeout in milliseconds (default: 10000)
   * @param privateMode - If true, uses private browsing mode (default: false)
   * @param newTab - If true, always creates a new tab (useful for parallel requests)
   * @param showWindow - If true, shows the browser window (default: false)
   * @returns Object containing the current URL, page title, and tab ID after navigation
   */
  public async open(url: string, timeout = 10000, privateMode = false, newTab = false, showWindow = false) {
    // Reject non-http(s) schemes (e.g. file://) and local/private hosts before navigating
    // (covers fetch() too, which routes through open()) to prevent local-file read / SSRF.
    url = sanitizeRemoteUrl(url)

View on GitHub (pinned to 726446b54c)

Solutions

  1. Retry createTab once, and if it still fails, surface a deterministic 'unable to create browser tab' error.
  2. Add an isDisposing guard so requests during teardown short-circuit instead of racing destruction.
  3. Check Electron logs for render-process/GPU crashes on BrowserView construction.
  4. Ensure getOrCreateWindow has fully settled (await ensureAppReady) before creating tabs.

Example fix

// before
const { tabId: newTabId } = await this.createTab(privateMode, showWindow)
const tab = windowInfo.tabs.get(newTabId)
if (!tab) {
  throw new Error(`Tab ${newTabId} was created but not found - it may have been closed`)
}

// after — single retry + teardown guard
let created = await this.createTab(privateMode, showWindow)
let tab = windowInfo.tabs.get(created.tabId)
if (!tab && !this.disposing) {
  created = await this.createTab(privateMode, showWindow)
  tab = windowInfo.tabs.get(created.tabId)
}
if (!tab) throw new Error('Unable to create browser tab (webContents destroyed)')
return { tabId: created.tabId, tab }
Defensive patterns

Strategy: try-catch

Validate before calling

async function ensureActiveTab(controller, windowInfo, privateMode, showWindow) {
  let created = await controller.createTab(privateMode, showWindow)
  let tab = windowInfo.tabs.get(created.tabId)
  if (!tab && !controller.disposing) {
    created = await controller.createTab(privateMode, showWindow)
    tab = windowInfo.tabs.get(created.tabId)
  }
  if (!tab) throw new Error('unable to create a usable browser tab')
  return { tabId: created.tabId, tab }
}

Try / catch

try {
  return await ensureActiveTab(controller, windowInfo, privateMode, showWindow)
} catch (e) {
  if (controller.disposing) throw new Error('browser controller shutting down')
  throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/34b7e7861480d66b. Report an issue: GitHub.