CherryHQ/cherry-studio · error · Error
Tab ${freshTabId} was created but not found - it may have be
Error message
Tab ${freshTabId} was created but not found - it may have been closed What it means
In the newTab branch of getActiveOrCreateTab, createTab resolves with a freshTabId but windowInfo.tabs.get(freshTabId) returns undefined immediately after. Since createTab sets windowInfo.tabs.set(tabId, tabInfo) before resolving, the only way it is missing is if the view's webContents 'destroyed' handler already fired and deleted the entry — a close race right after creation.
Source
Thrown at src/main/ai/mcp/servers/browser/controller.ts:570
* @param privateMode - Whether to use private browsing mode
* @param tabId - Optional specific tab ID to use
* @param newTab - If true, always create a new tab (useful for parallel requests)
* @param showWindow - If true, shows the browser window (default: false)
*/
private async getTab(
privateMode: boolean,
tabId?: string,
newTab?: boolean,
showWindow = false
): Promise<{ tabId: string; tab: TabInfo }> {
const windowInfo = await this.getOrCreateWindow(privateMode, showWindow)
// If newTab is requested, create a fresh tab
if (newTab) {
const { tabId: freshTabId } = await this.createTab(privateMode, showWindow)
const tab = windowInfo.tabs.get(freshTabId)
if (!tab) {
throw new Error(`Tab ${freshTabId} was created but not found - it may have been closed`)
}
return { tabId: freshTabId, tab }
}
if (tabId) {
const tab = windowInfo.tabs.get(tabId)
if (tab && !tab.view.webContents.isDestroyed()) {
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 }View on GitHub (pinned to 726446b54c)
Solutions
- Treat the missing tab as 'creation lost' and retry once via createTab, or surface a clear 'browser tab unavailable' error to the agent.
- Investigate why the webContents was destroyed instantly — check Electron GPU/sandbox logs and ensure the app is not shutting down.
- Avoid invoking browser tools during teardown; gate with ensureAppReady and an isDisposing flag.
- Serialize createTab calls per window to reduce destruction races.
Example fix
// before
const { tabId: freshTabId } = await this.createTab(privateMode, showWindow)
const tab = windowInfo.tabs.get(freshTabId)
if (!tab) {
throw new Error(`Tab ${freshTabId} was created but not found - it may have been closed`)
}
// after — retry once before giving up; detect teardown
let tab = windowInfo.tabs.get(freshTabId)
if (!tab) {
if (this.disposing) throw new Error('Browser controller is shutting down')
const retry = await this.createTab(privateMode, showWindow)
tab = windowInfo.tabs.get(retry.tabId)
}
if (!tab) throw new Error('Tab creation failed; webContents was destroyed immediately')
return { tabId: freshTabId, tab } Defensive patterns
Strategy: try-catch
Validate before calling
// Retry once when a freshly created tab is missing due to a destruction race
async function createTabStable(controller, windowInfo, privateMode, showWindow) {
const { tabId } = await controller.createTab(privateMode, showWindow)
let tab = windowInfo.tabs.get(tabId)
if (!tab && !controller.disposing) {
const retry = await controller.createTab(privateMode, showWindow)
tab = windowInfo.tabs.get(retry.tabId)
}
if (!tab) throw new Error('tab creation failed; webContents destroyed immediately')
return tab
} Try / catch
try {
return await createTabStable(controller, windowInfo, privateMode, showWindow)
} catch (e) {
if (controller.disposing) throw new Error('browser controller shutting down')
throw e
} Prevention
- Avoid browser-tool calls during shutdown; gate with an isDisposing flag.
- Serialize createTab per window to reduce destruction races.
- Investigate GPU/sandbox crashes if creation consistently fails.
When it happens
Trigger: A newly created BrowserView's webContents is destroyed synchronously or in the same tick after createTab resolves (GPU crash, forced sandbox teardown, app shutdown), triggering the 'destroyed' listener (controller.ts:480) which calls windowInfo.tabs.delete(tabId) before the caller reads it.
Common situations: Browser tool invoked during app quit/suspend; Electron sandbox or GPU process crash on view creation; a concurrent reset()/dispose() tearing down the window right as a new tab is spawned; resource exhaustion destroying the new view instantly.
Related errors
- Tab ${newTabId} was created but not found - it may have been
- MCP browser window not found after open
- Window not found for ${privateMode ? 'private' : 'normal'} m
- Tab ${tabId} not found
- Unknown script error
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/f5e391453212e102.
Report an issue: GitHub.