jackwener/OpenCLI · warning

[opencli] Failed to recover drifted tab: ${moveErr}

Error message

[opencli] Failed to recover drifted tab: ${moveErr}

What it means

Companion warning to the drift-detection warning: after detecting that a tab drifted to a different window during navigation, the chrome.tabs.move back to the session window (or the follow-up chrome.tabs.get) failed. The code catches moveErr and logs it rather than throwing, then continues using the tab wherever it currently is. Session window isolation may be broken for the remainder of the command.

Source

Thrown at extension/src/background.ts:1816

      timedOut = true;
      console.warn(`[opencli] Navigate to ${targetUrl} timed out after 15s`);
      finish();
    }, 15000);
  });

  let tab = await chrome.tabs.get(tabId);

  // Post-navigation drift detection: if the tab moved to another window
  // during navigation (e.g. a tab-management extension regrouped it),
  // try to move it back to maintain session isolation.
  const postNavigationSession = automationSessions.get(leaseKey);
  if (postNavigationSession && tab.windowId !== postNavigationSession.windowId) {
    console.warn(`[opencli] Tab ${tabId} drifted to window ${tab.windowId} during navigation, moving back to ${postNavigationSession.windowId}`);
    try {
      await chrome.tabs.move(tabId, { windowId: postNavigationSession.windowId, index: -1 });
      tab = await chrome.tabs.get(tabId);
    } catch (moveErr) {
      console.warn(`[opencli] Failed to recover drifted tab: ${moveErr}`);
    }
  }

  return pageScopedResult(cmd.id, tabId, { title: tab.title, url: tab.url, timedOut });
}

async function handleTabs(cmd: Command, leaseKey: string): Promise<Result> {
  const session = automationSessions.get(leaseKey);
  if (session && !session.owned && cmd.op !== 'list') {
    return {
      id: cmd.id,
      ok: false,
      errorCode: 'bound_tab_mutation_blocked',
      error: `Session "${session.session}" is bound to a user tab; tab new/select/close requires an owned OpenCLI session.`,
      errorHint: 'Unbind the session first, or use a different session for owned OpenCLI tabs.',
    };
  }
  switch (cmd.op) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the command; a fresh navigation usually re-anchors the tab correctly.
  2. Verify the session window still exists (chrome.windows.get) and that no extension closed it; reopen the browser profile if windows were closed.
  3. Disable competing tab-management extensions that close or pin windows during automation.
  4. Check the extension has the 'tabs' (and 'debugger' where needed) permissions in extension/src/manifest.

Example fix

// before: catch (moveErr) { console.warn(`[opencli] Failed to recover drifted tab: ${moveErr}`); }
// after (user-side workaround): rerun with competing tab extensions disabled so the move succeeds
Defensive patterns

Strategy: try-catch

Validate before calling

try { await chrome.windows.get(session.windowId); } catch { /* session window gone — recreate before moving tab */ }

Type guard

function canRecover(tab, session) {
  return Boolean(tab && session?.windowId != null && tab.id != null);
}

Try / catch

try {
  await chrome.tabs.move(tabId, { windowId: session.windowId, index: -1 });
} catch (moveErr) {
  console.warn(`[opencli] Failed to recover drifted tab: ${moveErr}`);
  // fallback: recreate the tab in the session window or rerun the command
}

Prevention

When it happens

Trigger: chrome.tabs.move(tabId, { windowId: session.windowId, index: -1 }) rejects — e.g. the tab was closed during recovery, the target window no longer exists, the extension lacks the 'tabs' permission, or the tab is of a type that cannot be moved (pinned/protected windows).

Common situations: Target window closed by the user or another extension between drift detection and the move; a tab-pinning extension holds the tab; Chrome refuses to move tabs into windows with different profiles; the tab id became stale because navigation replaced it.

Related errors


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