{"record":{"id":"95a142423d573473","repo":"jackwener/OpenCLI","slug":"bound-tab-gone","errorCode":"bound_tab_gone","errorMessage":"Bound tab for session \"${existingSession.session}\" no longer exists.","messagePattern":"Bound tab for session \"(.+?)\" no longer exists\\.","errorType":"error_code","errorClass":"CommandFailure","httpStatus":null,"severity":"error","filePath":"extension/src/background.ts","lineNumber":1520,"sourceCode":"        // Try to move it back instead of abandoning it.\n        console.warn(`[opencli] Tab ${tabId} drifted to window ${tab.windowId}, moving back to ${session.windowId}`);\n        try {\n          await chrome.tabs.move(tabId, { windowId: session.windowId, index: -1 });\n          const moved = await chrome.tabs.get(tabId);\n          if (moved.windowId === session.windowId && isDebuggableUrl(moved.url)) {\n            return { tabId, tab: moved };\n          }\n        } catch (moveErr) {\n          console.warn(`[opencli] Failed to move tab back: ${moveErr}`);\n        }\n      } else if (!isDebuggableUrl(tab.url)) {\n        console.warn(`[opencli] Tab ${tabId} URL is not debuggable (${tab.url}), re-resolving`);\n      }\n    } catch (err) {\n      if (err instanceof CommandFailure) throw err;\n      if (existingSession && !existingSession.owned) {\n        automationSessions.delete(leaseKey);\n        throw new CommandFailure(\n          'bound_tab_gone',\n          `Bound tab for session \"${existingSession.session}\" no longer exists.`,\n          'Run \"opencli browser bind\" again, then retry the command.',\n        );\n      }\n      console.warn(`[opencli] Tab ${tabId} no longer exists, re-resolving`);\n    }\n  }\n\n  const existingPreferredTabId = existingSession?.preferredTabId ?? null;\n  if (existingSession && existingPreferredTabId !== null) {\n    const session = existingSession;\n    try {\n      const preferredTab = await chrome.tabs.get(existingPreferredTabId);\n      if (isDebuggableUrl(preferredTab.url)) return { tabId: preferredTab.id!, tab: preferredTab };\n      if (!session.owned) {\n        throw new CommandFailure(\n          'bound_tab_not_debuggable',","sourceCodeStart":1502,"sourceCodeEnd":1538,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/extension/src/background.ts#L1502-L1538","documentation":"During tab re-resolution, chrome.tabs.get for the candidate tab threw (tab was closed or unreachable) while an existing unowned bound session pointed at it. The library deletes the stale lease and throws bound_tab_gone so the caller knows the session binding is dead and must be recreated.","triggerScenarios":"chrome.tabs.get(tabId) rejects inside resolveTab's catch block for a tab belonging to an existing unowned (bound) session — i.e. the user closed the bound tab before the command ran.","commonSituations":"User closes the tab that 'opencli browser bind' bound to, then runs another opencli browser command; tab discarded by window close; tab crashed.","solutions":["Re-run 'opencli browser bind' to create a fresh binding, then retry the command","Reopen the tab if it was closed accidentally and rebind","Check that the browser window containing the bound tab is still open","Avoid closing the bound tab while automation sessions reference it"],"exampleFix":"// before\nTab closed → bound_tab_gone\n// after\nopencli browser bind   // rebind to a live tab, then retry the original command","handlingStrategy":"retry","validationCode":"let tabExists = false;\ntry { await chrome.tabs.get(tabId); tabExists = true; } catch {}\nif (!tabExists) await rebind();","typeGuard":"async function tabExists(tabId: number): Promise<boolean> {\n  try { await chrome.tabs.get(tabId); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  await cmd();\n} catch (e) {\n  if ((e as Error).message.includes('no longer exists')) { await opencliBind(); await retry(cmd); }\n  else throw e;\n}","preventionTips":["Don't close tabs while a bind session is active","Re-bind after browser restarts","Check tab existence before each automated step","Keep bound tabs in a dedicated window"],"tags":["chrome-extension","tab-lifecycle","session-binding"],"backgroundTag":"bound-tab-gone","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}