jackwener/OpenCLI · error · CommandFailure

bound_tab_gone

bound_tab_gone

Error message

Bound tab for session "${existingSession.session}" no longer exists.

What it means

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.

Source

Thrown at extension/src/background.ts:1520

        // Try to move it back instead of abandoning it.
        console.warn(`[opencli] Tab ${tabId} drifted to window ${tab.windowId}, moving back to ${session.windowId}`);
        try {
          await chrome.tabs.move(tabId, { windowId: session.windowId, index: -1 });
          const moved = await chrome.tabs.get(tabId);
          if (moved.windowId === session.windowId && isDebuggableUrl(moved.url)) {
            return { tabId, tab: moved };
          }
        } catch (moveErr) {
          console.warn(`[opencli] Failed to move tab back: ${moveErr}`);
        }
      } else if (!isDebuggableUrl(tab.url)) {
        console.warn(`[opencli] Tab ${tabId} URL is not debuggable (${tab.url}), re-resolving`);
      }
    } catch (err) {
      if (err instanceof CommandFailure) throw err;
      if (existingSession && !existingSession.owned) {
        automationSessions.delete(leaseKey);
        throw new CommandFailure(
          'bound_tab_gone',
          `Bound tab for session "${existingSession.session}" no longer exists.`,
          'Run "opencli browser bind" again, then retry the command.',
        );
      }
      console.warn(`[opencli] Tab ${tabId} no longer exists, re-resolving`);
    }
  }

  const existingPreferredTabId = existingSession?.preferredTabId ?? null;
  if (existingSession && existingPreferredTabId !== null) {
    const session = existingSession;
    try {
      const preferredTab = await chrome.tabs.get(existingPreferredTabId);
      if (isDebuggableUrl(preferredTab.url)) return { tabId: preferredTab.id!, tab: preferredTab };
      if (!session.owned) {
        throw new CommandFailure(
          'bound_tab_not_debuggable',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run 'opencli browser bind' to create a fresh binding, then retry the command
  2. Reopen the tab if it was closed accidentally and rebind
  3. Check that the browser window containing the bound tab is still open
  4. Avoid closing the bound tab while automation sessions reference it

Example fix

// before
Tab closed → bound_tab_gone
// after
opencli browser bind   // rebind to a live tab, then retry the original command
Defensive patterns

Strategy: retry

Validate before calling

let tabExists = false;
try { await chrome.tabs.get(tabId); tabExists = true; } catch {}
if (!tabExists) await rebind();

Type guard

async function tabExists(tabId: number): Promise<boolean> {
  try { await chrome.tabs.get(tabId); return true; } catch { return false; }
}

Try / catch

try {
  await cmd();
} catch (e) {
  if ((e as Error).message.includes('no longer exists')) { await opencliBind(); await retry(cmd); }
  else throw e;
}

Prevention

When it happens

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

Common situations: User closes the tab that 'opencli browser bind' bound to, then runs another opencli browser command; tab discarded by window close; tab crashed.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/95a142423d573473. Report an issue: GitHub.